G1GC OutOfMemory too early
Asked Answered
D

2

6

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 .

Demurral answered 29/8, 2017 at 12:51 Comment(5)
How did you calculate used memory sizes?Inesinescapable
-XX:+PrintGCDetails prints the Heap state as you can see in my question total 2097152K, used 1048100K. I checked that both on Windows and Linux. The behaviour is the sameDemurral
I meant the required memory by your code....Inesinescapable
Also, show us the exception, which line was it thrown from?Inesinescapable
That was line array[i] = new int[1024 * 1024 / 4];. Here it's the place that definitely causes OOM. But usually OOM can be thrown from any place that dosn't have anything to do with the root cause of that OOM.Demurral
G
8

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.

Grating answered 29/8, 2017 at 15:11 Comment(0)
A
2

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

Aliphatic answered 30/8, 2017 at 12:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.