简体   繁体   中英

Java G1 garbage collector generates Java inconsistencies?

I recently tried to activate the garbage-first garbage collector and evaluate it. As a start I wrote this code, trying to produce an java.lang.OutOfMemoryError :

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class G1Test {
  public static void floodMemory() {
    int i = 0;
    try {
      // allocate an array where we will just store a lot of java objects
      List<Date> l = new ArrayList<Date>();
      for (; i < 1051366050; i++) {
        l.add(new Date());
      }
    } catch (Throwable t) {
      System.err.println("Throwable in floodMemory!");
      System.out.println("i=" + i);
      t.printStackTrace();
    }
  }

  public static void main(String[] args) {
    try {
      System.out.println("Started memory flooding.");
      floodMemory();
      System.out.println("Sleeping.");
      Thread.sleep(Long.MAX_VALUE);
    } catch (Throwable t) {
      System.err.println("Throwable in main!");
      t.printStackTrace();
    }
  }
}

... and I ran the code using two scenarios:

Case 1. With these flags: -Xmx4096M -XX:+UseG1GC , I get this output:

Started memory flooding.
    Throwable in main!
    java.lang.OutOfMemoryError: Java heap space
    at com.siemens.scr.usi.experimental.G1Test.floodMemory(G1Test.java:14)
    at com.siemens.scr.usi.experimental.G1Test.main(G1Test.java:26)

... which means that an the infamous OutOfMemoryError is thrown somewhere BUT captured in the main method.

Case 2. With this flag: -Xmx4096M , I get this output:

Started memory flooding.
Throwable in floodMemory!
i=105136605
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2245)
    at java.util.Arrays.copyOf(Arrays.java:2219)
    at java.util.ArrayList.grow(ArrayList.java:242)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
    at java.util.ArrayList.add(ArrayList.java:440)
    at com.siemens.scr.usi.experimental.G1Test.floodMemory(G1Test.java:14)
    at com.siemens.scr.usi.experimental.G1Test.main(G1Test.java:26)
Sleeping.

... which means that the exception is caught where I was expecting it to be caught.

Notes:

  1. The code is pure experimental and doesn't follow any specific purpose - it is just to observe the behavior.
  2. The code ran using Oracle JDK 1.7.0 update 60, 64 bit on Windows 7 Enterprise running on top of a Dell Precision M4700.

The question is if somebody can explain this behavior - couldn't find any similar posts nor any bug report (my issue being the lack of consistency).

This is just a theory, but it may not have anything to do with the garbage collection settings, at least not directly:

In the first case (-Xmx4096M -XX:+UseG1GC): the OutOfMemoryError could've been thrown in the method floodMemory, as expected, but since you're all ready at an OutOfMemory state, it may be possible that another OutOfMemoryError was thrown within the catch block of the floodMemory method. It may be possible that the second one is being thrown at the System.err command, which is why you don't see the output of the first. This error then gets propagated to the main method.

In the second case, the Garbage Collector might've been able to free enough memory for the System.err to execute and the rest of your application to finish.

Again, this is just a theory. I tried running the first case with Java 1.7 and eventually my program just hung and I didn't see an exception thrown.

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