2013-09-25 35 views
4

我正在使用JVM進行科學應用。我的過程中的第一步是將大量數據加載到很少的double[]數組(大圖中每個節點的48個元素的數組)。很久以前,我發現是否有足夠的內存來加載它們,Java漸近地減速,jvisualvm告訴我這是因爲幾乎所有的CPU時間都花費在垃圾回收中:加載數據時達到飽和點;我如何控制Java GC代?

enter image description here

第一分鐘左右是好的:「使用的堆」(右圖)跳向上和向下,因爲它生長,因爲有些對象是臨時的(我在斯卡拉寫這個),有些對象是永久性的。然而,在那之後,數據加載會停下來,因爲垃圾收集器顯然是一遍又一遍地檢查同一個對象(左圖)。它一定會期待它們超出範圍,但我將它們保留在範圍之內,因爲我想將它們用於我的分析。

我知道垃圾收集器根據它們的生存可能性將對象放在不同的世代中。第一代包含最近創建並很快可能死亡的對象;後代人越來越有可能長壽。如果我的對象在第一代出現錯誤,是否有任何方法告訴垃圾回收者他們應該在後一代?我知道我會保持他們 - 我怎麼能告訴垃圾收集器?

儘管我希望這些物體處於更持久的一代,但PermGen會過於沉重:經過數十分鐘的處理後,它們將最終死亡。 (我想在Hadoop的減速,這可能這一個沒有新的JVM後,在不同的塊數據的工作,用這個。)

注:我使用的是Sun的HotSpot VM:

% java -version 
java version "1.6.0_45" 
Java(TM) SE Runtime Environment (build 1.6.0_45-b06) 
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode) 

校正(到以前的編輯):更改-Xmx確實變化的飽和點,但顯然Java的,如果它是在-jar爭吵後通過忽略-Xmx命令行參數。也就是說,不要

java -Xmx2048 -jar MyJarFile.jar 

而不是

java -jar MyJarFile.jar -Xmx2048 

正因爲如此,我被錯誤地診斷相對於最大堆行爲和所有指向-Xmx標誌的答案是有效的。

我描述的飽和點發生在「堆大小」(右圖上的橙色)達到所選-Xmx限制時,「堆大小」始終是「使用堆」的1.6倍(右圖中的藍色)除非你用-XX:NewRatio-XX:OldSize明確設置「舊」代的大小。這些也需要在-jar的論點之前,並且它們提供了很多控制。

+2

難道你不能重新使用這些對象嗎? – exussum

+0

「重新使用對象」?你是什​​麼意思?我將它們加載到內存中,對它們進行分析。它們代表不同的數據。 –

+0

它們可能代表不同的數據,但它們可能是同一個對象。 a = 12和b = 1534545是不同的,但如果我沒有在同一時間使用它們,我可以重新使用一個而不是創建一個「新」b並在gc上調用 – exussum

回答

1

我想你應該使用JVisualVM的VisualGC插件來檢查它,這樣你就可以看到不同的世代是如何被使用的。根據屏幕截圖,似乎老一代已經填滿了(因爲堆沒有完全裝滿,但GC正在努力工作),所以GC正在艱難時期釋放內存。您應該增加堆或調整-XX:NewRatio代的大小,您也可以嘗試調整tenuring treshold以控制對象何時被視爲「舊」。

+0

這實際上是發生了什麼事情:堆空間不滿,但「舊」一代是。 (GC正確地將我的數據標記爲「舊」,但「舊」已滿,我不明白爲什麼GC在努力工作而不是失敗。) VisualGC插件對於診斷情況,並且'-XX:NewRatio'及其親屬(例如'-XX:OldSize')對於將GC調整爲大內存計算特別有用。 謝謝! –

5

GC不應該以螺旋方式調用它自己,除非堆已接近飽和狀態。您需要增加最大堆大小(-Xmx) - 從接近2x的預期保留時間開始。您也可以使用CMS收集器,這可以改善大型終身設置的情況。你也可能需要手動調整你的新一代,因爲老一代不需要定期清理。

您也可以考慮使用NIO直接ByteBuffers。雖然它們是爲了更高效的I/O操作而設計的,但它們對於長壽命和寬存儲器陣列來說是一個合理的選擇。

0

如果對象仍在被引用,則不會收集垃圾。所以只要保留一個對象的引用,直到你想讓它們被垃圾回收。

相關問題