简体   繁体   中英

G1GC OutOfMemory too early

My test code:

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");
  }
}

I launch it with arguments in java 8 -Xmx2048m -XX:+UseG1GC -XX:+PrintGCDetails

And it fails with OutOfMemory when only 1G is consumed.

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

I see that G1 allocated size is 2G and I suppose JVM is trying to allocate more and fails with OOM. But why is it trying to allocate more if half of the memory is free?

With UseConcMarkSweepGC it's working fine and array was fully filled .

I'm pretty sure this happens due to Humongous Allocations .
If you add this option

-XX:+PrintAdaptiveSizePolicy

you will be able to see that most of the allocations are of 1048592 bytes which fits neither 50% nor even 100% of a single G1 region (which as seen in the output is 1024K=1048576 bytes). I assume that means that every array occupies at least two regions. Since it is a humongous allocation most of the free space in the second region cannot be used. This quickly causes extreme heap fragmentation making further allocations impossible.

Agree with @yegodm. Solution is to increase the Heap region with -XX:G1HeapRegionSize to make sure previous Humongous objects are no longer Humongous and will follow the regular allocation path. Read more about humongous object allocation here 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM