2010-10-23 18 views
1

問候所有,我想知道是否有人可以提供某種解釋或確認我的猜測。使用JRE -Xms300m將執行時間縮短一半?

我有一個for循環程序執行了幾百次,每次添加數字到ArrayLists的選擇。對於爲什麼要花費這麼長時間來執行我進一步調查感到困惑。

事實證明,如果我有

(for int i =0; i < 50000; i++) 

這將需要近一倍這將需要時間,如果我有

(for int i=0; i < 40000; i++) 

增加i超過50000甚至高達100000居然沒需要很多額外的時間。剛剛在40000和50000之間的某個地方跳了大跳

把我的思考放在頭上,我猜想可能是因爲某個地方的內存不足而導致內存不足的問題?並且需要更多的記憶,儘管我不確定爲什麼會這麼長時間。

無論如何,我發現通過添加JRE參數-Xms300m它解決了這個問題。我認爲這是以300mb的堆大小啓動程序,因此否定了稍後分配額外堆空間的需要。

我還不明白的是,我爲arrayLists創建了足夠多的內存。我認爲這個問題會在我分配堆的內存時發生,而不是當我使用.add()方法時。

new ArrayList<Integer>(5000); 
+1

只是出於好奇,會發生什麼,如果在運行循環之前調用ArrayList.ensureCapacity(INT),預留足夠的內存用於所有的數字前面? – vanza 2010-10-24 00:27:33

回答

2

通過指定的初始大小爲ArrayList你預留空間引用的元素,而不是元素本身。每次您撥打add()時,都會創建一個新的Integer對象並將其添加到底層數組中,並且很可能這些對象正在佔用您的堆。

我有點驚訝,只是添加-Xms300m幫助 - 這臺最小堆大小,但沒有還設置最大(與-Xmx),您通常會看到一個錯誤:

$ java -Xms300m blah 
Error occurred during initialization of VM 
Incompatible minimum and maximum heap sizes specified 

當一個Java應用程序創建了大量的對象和方法堆限制,在JVM開始執行垃圾回收(GC),基本上包括兩個步驟:

  • 狩獵是對象不再被使用,並且可以被釋放
  • 將已經存在一段時間的對象合併到堆的不同部分(「舊」或「老生代」) - 這意味着將來的GC運行可以忽略這些對象,提高了性能

有很多深入的文檔的基於Java的GC機制(包括daddy of them all),但對於初學者來說,看到發生的事情在你的程序嘗試添加-verbose:gc標誌。這會在每次垃圾收集器啓動時輸出一行,告訴您需要多長時間才能運行,並釋放了多少內存,這可能會爲您提供有關當您增加迭代次數時堆中發生的事情的線索。

+0

乾杯人,真的很有幫助。詳細:gc我可以看到,沒有-Xms300m我得到了10行,而不是4.使用-Xms1000m我仍然得到4行,所以我假設它不管GC在什麼時候。 – John 2010-10-24 00:38:29

+0

另外,我假設GC經常完成(而不是隻抓取更多的堆內存)來降低程序的內存使用量? – John 2010-10-24 00:46:22

+0

我很好奇,如果我做--Xms120 -Xmx120我其實從來沒有用完堆。然而,隨着GC的發生,我的程序需要更長時間才能執行。是否有辦法將GC關閉?我正在編寫一個程序,它必須儘可能快地執行 – John 2010-10-24 00:56:03

2

耶士,將-Xms選項指定起始堆空間。如果這加快了你的問題,這是一個很好的選擇,你正在運行內存分配/垃圾收集問題。注意ArrayList API:

「每個ArrayList實例都有一個容量,容量是用於存儲列表中元素的數組大小,它總是至少與列表大小一樣大。到一個ArrayList,它的容量會自動增長,增長策略的細節沒有被指定,除了添加一個元素具有不變的攤銷時間成本這一事實,

一個應用程序可以在添加一個大數字之前增加一個ArrayList實例的容量在使用ensureCapacity操作元素。這可以減少增量再分配的數量。 「

那麼,如何ArrayList添加內存是JVM的實現細節,但具有不變攤銷成本。

我敢打賭,你是你的陣列中創建對象,40K和迭代之間的50K程序試圖GC,失敗,再加入更多的堆。指定一個較高的最低會耽誤GC和更多的堆創作......

+0

乾杯人,我認爲你是對的。最後一段會解釋很多 – John 2010-10-24 00:43:59

0

@ hvgotcodes的回答這樣說:

I bet you are creating objects in your array, that between 40k and 50k iterations your program was trying to GC, failing, then adding more heap. Specifying a higher minimum would delay GC and more heap creations...

這是接近標準,但可能不完全正確。

在Java 1.6 JVM的熱點,堆會在兩種情況下得到擴展:

  1. 垃圾收集後,仍然有沒有足夠的自由空間來分配觸發GC的對象。

  2. 垃圾收集之後,自由空間的量以及所使用的空間的量之間的比小於一給定值。默認比例是40%,但可以調整。

在OP的例子中,很難知道發生了什麼。但是,不難想象第一條規則從未應用的應用程序。例如,某些應用程序可能會將當前堆填充到99%,然後保留大量的小對象。沒有第二條規則,堆不會擴大,整體性能會受到影響。