JavaG1垃圾收集器是否生成Java不一致?

JavaG1垃圾收集器是否生成Java不一致?,java,garbage-collection,g1gc,Java,Garbage Collection,G1gc,我最近尝试激活垃圾第一垃圾收集器并对其进行评估。首先,我编写了这段代码,试图生成一个java.lang.OutOfMemoryError: import java.util.ArrayList; 导入java.util.Date; 导入java.util.List; 公开课G1考试{ 公共静态空泛洪存储器(){ int i=0; 试一试{ //分配一个数组,我们将只在其中存储大量java对象 列表l=新的ArrayList(); 对于(;i

我最近尝试激活垃圾第一垃圾收集器并对其进行评估。首先,我编写了这段代码,试图生成一个
java.lang.OutOfMemoryError

import java.util.ArrayList;
导入java.util.Date;
导入java.util.List;
公开课G1考试{
公共静态空泛洪存储器(){
int i=0;
试一试{
//分配一个数组,我们将只在其中存储大量java对象
列表l=新的ArrayList();
对于(;i<1051366050;i++){
l、 添加(新日期());
}
}捕获(可丢弃的t){
System.err.println(“可在泛洪存储器中丢弃!”);
System.out.println(“i=“+i”);
t、 printStackTrace();
}
}
公共静态void main(字符串[]args){
试一试{
System.out.println(“启动内存溢出”);
泛洪存储器();
System.out.println(“睡眠”);
线程睡眠(长.MAX_值);
}捕获(可丢弃的t){
System.err.println(“在main中可丢弃!”);
t、 printStackTrace();
}
}
}
。。。我使用两种场景运行代码:

案例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)
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.
。。。这意味着异常在我希望捕获的地方被捕获

注:

  • 该代码纯粹是实验性的,没有遵循任何特定的目的——它只是为了观察行为
  • 该代码在运行Dell Precision M4700的Windows 7 Enterprise上使用Oracle JDK 1.7.0 update 60 64位运行

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

    这只是一个理论,但可能与垃圾收集设置无关,至少不是直接的:

    在第一种情况下(-Xmx4096M-XX:+UseG1GC):OutOfMemoryError可能已在方法floodMemory中抛出,正如预期的那样,但由于您都已准备好处于OutOfMemory状态,可能在floodMemory方法的catch块中抛出了另一个OutOfMemoryError。第二个可能是在System.err命令中抛出的,这就是为什么您看不到第一个的输出。然后,此错误会传播到main方法

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


    同样,这只是一个理论。我试着用Java1.7运行第一个案例,最终我的程序挂起,没有看到抛出异常

    您能否对同一收集器始终重复相同的行为?如果您没有在main中捕获异常,它是否会被捕获并按预期报告。请注意,异常可能发生在
    new Date()
    操作中,而不是在
    add
    中,这是堆栈跟踪的原因。我不知道“垃圾优先”应该做什么,但可能是因为内存不足,内部的
    catch
    无法处理异常。@JigarJoshi-是的,这种行为可以重复。我之所以把所有代码都放在这里,是因为我希望其他人可以运行并确认。@ScaryWombat-异常在两个不同的地方被捕获。我的期望是
    floodMemory
    方法不会泄露任何信息,包括OEM。传统上,堆算法“阻止”了一定数量的堆,这些堆只有在OOM发生时才可用。(对于堆栈溢出也是如此。)但是选择“正确”的存储量来“保留”是相当棘手的,如果堆管理算法发生变化,存储量很可能会发生变化。有人怀疑G1GC实现没有适当地“调整”这个“旋钮”。这是一个好的观点。我想从我的答案中得到的是,第二个异常很可能出现在catch块内部。