2014-04-16 32 views
1

我正在對HashMap,LinkedHashMap插入進行一些性能測試。我正在測試的操作是在插入後在內存中插入和放大。如何在HashMap和LinkedHashMap中插入數據後計算內存中的大小?

我能夠做到的,插入測試也能夠與下面的邏輯來提取size in memory after insertion以及 -

long myTotalMemoryBefore = Runtime.getRuntime().totalMemory(); 

/* Fill the hashmap or linkedhashmap */ 

long myTotalMemoryAfter = Runtime.getRuntime().totalMemory(); 
long myHashMapMemory = myTotalMemoryAfter - myTotalMemoryBefore; 

我有一個包含2個億,他們的這種格式的頻率英語單詞的文本文件 - 在HashMap

hello 100 
world 5000 
good 2000 
bad 9000 
... 

現在我讀通過該行文件中的行並將其存儲和LinkeddHashMap所以我能夠與下面測量插入後,在內存中插入性能和大小,以及代碼。

我有,我有兩個方法,一個是HashMap等爲LinkedHashMap性能測試,他們都按順序運行,首先HashMap的測試將運行一個單一的類文件,然後LinkedHashMap的測試預訂購運行 -

public void hashMapTest() { 

    Map<String, String> wordTest = new HashMap<String, String>(); 

    long myTotalMemoryBefore = Runtime.getRuntime().totalMemory(); 
    String line = reader.readLine(); 
    while (line != null && !line.isEmpty()) { 
     // split the string on whitespace 
     String[] splittedString = line.split("\\s+"); 
     String split1 = splittedString[0].toLowerCase().trim(); 
     Integer split2 = Integer.parseInt(splittedString[1].trim()); 
     // now put it in HashMap as key value pair 
     wordTest.put(split1, split2); 
     line = reader.readLine(); 
    } 

    long myTotalMemoryAfter = Runtime.getRuntime().totalMemory(); 
    long myHashMapMemory = (myTotalMemoryAfter - myTotalMemoryBefore)/1024;  

    System.out.println(myHashMapMemory); 

} 

public void linkedHashMapTest() { 

    Map<String, String> wordTest = new LinkedHashMap<String, String>(); 

    long myTotalMemoryBefore = Runtime.getRuntime().totalMemory(); 
    String line = reader.readLine(); 
    while (line != null && !line.isEmpty()) { 
     // split the string on whitespace 
     String[] splittedString = line.split("\\s+"); 
     String split1 = splittedString[0].toLowerCase().trim(); 
     Integer split2 = Integer.parseInt(splittedString[1].trim()); 
     // now put it in LinkedHashMap as key value pair 
     wordTest.put(split1, split2); 
     line = reader.readLine(); 
    } 

    long myTotalMemoryAfter = Runtime.getRuntime().totalMemory(); 
    long myLinkedHashMapMemory = (myTotalMemoryAfter - myTotalMemoryBefore)/1024;  

    System.out.println(myLinkedHashMapMemory); // this is coming as zero always or negative value 

} 

還有我看到一個很奇怪的問題 - 對於HashMap的性能測試中,我可以看到myHashMapMemory中有一定的價值,但在myLinkedHashMapMemory變量,它總是零或負值。

任何想法爲什麼會發生這種情況,以及如何避免這個問題?一般來說,爲什麼我看到零或負值?

回答

1

要測量使用的內存,我們需要關閉線程分配緩衝-XX:-UseTLAB,則如本

Runtime rt = Runtime.getRuntime(); 
    long m0 = rt.totalMemory() - rt.freeMemory(); //used memory 
    Object obj = new Object(); 
    long m1 = rt.totalMemory() - rt.freeMemory(); 
    System.out.println(m1 - m0); 

將顯示內存java.lang.Object中的正確尺寸 - 在我的情況下,16個字節

+0

我們可以從命令行傳遞這個參數嗎?'-XX:-UseTLAB',因爲我將從命令提示符運行我的可運行jar?而且,我應該使用freeMemory而不是totalMemory? – john

+0

1)是的,java -XX ....; 2)freeMemory在我的簡單情況下是可以的,但最好使用usedMemory = runtime.totalMemory() - runtime.freeMemory()) –

0

快速提問:爲什麼有兩個相同的方法......?只需傳入地圖作爲參數?但是,如果你按順序運行它們,到達第二個方法的時候,gc可能會從第一個哈希映射中踢入並刪除東西。任何基於這種粗略方法的內存掃描都不會給你一個正確的估計。

換句話說:如果第二張地圖已被gc-ed處理,則第二張地圖可能會佔用與第一張地圖相同的存儲空間。此外,根據jvm和設置的不同,如果jvm未被使用(例如在其中的所有內容已被gc-ed處理之後),則jvm實際上可以將內存歸還給操作系統。

0

這可能是因爲其他人提到的gc行爲。 我想說的是對於如此大量的數據,兩個地圖的實現都很糟糕。我已經測試過,無論何時數據大於幾百萬字節,您都必須自己實現Map接口來完成這種工作。

0

我認爲Evgeniy是正確的。在jdk1.7中,TLAB被設置爲true。當一個新線程啓動時,TLAB將被分配,甚至不會創建對象。因此,您可以關閉TLAB並重試。 由於gc因素,你應該嘗試更多次,並且你最好提高Eden區域的空間以避免年輕的gc。

+0

謝謝:如何增加Eden區域的大小以避免使用Young GC。有什麼想法嗎? – john

+0

您可以使用-Xmn參數,例如:-Xmx2048M -Xms2048M -Xmn1024M。young:old的默認比例爲1:2,所以您只能提高-Xmx和-Xms,您還可以指定young只要-Xmn小於-Xmx/-Xms即可。 – blackteal

相關問題