Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 .

like image 254
Eugene To Avatar asked Aug 29 '17 12:08

Eugene To


2 Answers

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.

like image 161
yegodm Avatar answered Oct 20 '22 16:10

yegodm


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 here1

like image 29
Fairoz Avatar answered Oct 20 '22 17:10

Fairoz