2017-08-29 74 views
5

我的測試代碼:G1GC內存不足太早

int SIZE = 1900; 
int[][] array = new int[SIZE][]; 
for (int i = 0; i < SIZE; i++) { 
    array[i] = new int[1024 * 1024/4]; // 1MB 
    Thread.sleep(10); 
    if (i % 100 == 0 && i != 0) { 
    System.out.println(i + "Mb added"); 
    } 
} 

我帶參數運行它在Java 8 -Xmx2048m -XX:+UseG1GC -XX:+PrintGCDetails

它失敗,內存不足時,只有1G被消耗。

Heap 
garbage-first heap total 2097152K, used 1048100K [0x0000000080000000, 0x0000000080104000, 0x0000000100000000) 
region size 1024K, 1 young (1024K), 0 survivors (0K) 
Metaspace  used 3273K, capacity 4496K, committed 4864K, reserved 1056768K 
class space used 358K, capacity 388K, committed 512K, reserved 1048576K 

我看到G1分配的大小是2G,我想JVM試圖分配更多,並與OOM失敗。但是,如果內存的一半是免費的,它爲什麼要分配更多?

UseConcMarkSweepGC它工作正常,數組完全填充。

+0

您是如何計算使用內存大小的? –

+0

-XX:+ PrintGCDetails打印堆狀態,如您在我的問題總共2097152K,使用1048100K'中看到的那樣。我檢查了Windows和Linux。行爲是一樣的 –

+0

我的意思是你的代碼所需的內存.... –

回答

6

我很確定這是因爲Humongous Allocations
如果添加此選項

-XX:+ PrintAdaptiveSizePolicy

,你將能夠看到,大部分的分配是1048592個字節,這既不符合50%也不是一個甚至100%單個G1區(在輸出中看到的是1024K = 1048576字節)。我認爲這意味着每個陣列至少佔用兩個區域。由於這是一個龐大的分配,所以第二個地區的大部分空閒空間都不能使用。這很快就會導致極度堆碎片,從而無法進一步分配。

1

同意@yegodm。解決方法是使用-XX:G1HeapRegionSize增加Heap區域,以確保先前的Humongous對象不再是Humongous,並且將遵循常規分配路徑。在這裏閱讀更多有關大量物體分配的信息1