Java G1垃圾收集器会产生Java不一致吗?

时间:2020-12-15 01:34:05

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:

我最近尝试激活垃圾优先垃圾收集器并对其进行评估。作为开始,我编写了这段代码,尝试生成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:

情况1.使用这些标志:-Xmx4096M -XX:+ UseG1GC,我得到这个输出:

    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.

...这意味着臭名昭着的OutOfMemoryError被抛出在主方法中捕获的某处。

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

情况2.使用此标志:-Xmx4096M,我得到此输出:

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. 代码纯粹是实验性的,不遵循任何特定目的 - 只是观察行为。

  3. 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.
  4. 该代码使用在Dell Precision M4700上运行的Windows 7 Enterprise上的Oracle JDK 1.7.0更新60,64位运行。

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).

问题是,是否有人可以解释这种行为 - 找不到任何类似的帖子或任何错误报告(我的问题是缺乏一致性)。

1 个解决方案

#1


0  

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.

在第一种情况下(-Xmx4096M -XX:+ UseG1GC):OutOfMemoryError可能已经按预期抛出在方法floodMemory中,但由于你已经准备好处于OutOfMemory状态,可能会抛出另一个OutOfMemoryError在floodMemory方法的catch块中。有可能第二个被抛出System.err命令,这就是你没有看到第一个输出的原因。然后,此错误将传播到main方法。

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.

在第二种情况下,垃圾收集器可能已经能够释放足够的内存以供System.err执行并完成其余的应用程序。

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.

同样,这只是一个理论。我尝试用Java 1.7运行第一个案例,最后我的程序挂了,我没有看到抛出的异常。

#1


0  

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.

在第一种情况下(-Xmx4096M -XX:+ UseG1GC):OutOfMemoryError可能已经按预期抛出在方法floodMemory中,但由于你已经准备好处于OutOfMemory状态,可能会抛出另一个OutOfMemoryError在floodMemory方法的catch块中。有可能第二个被抛出System.err命令,这就是你没有看到第一个输出的原因。然后,此错误将传播到main方法。

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.

在第二种情况下,垃圾收集器可能已经能够释放足够的内存以供System.err执行并完成其余的应用程序。

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.

同样,这只是一个理论。我尝试用Java 1.7运行第一个案例,最后我的程序挂了,我没有看到抛出的异常。