GC不清除范围内的对象

Jat*_*tin 4 java jit java-8

我早就读了一篇文章,我似乎找不到它.它解释了以下行为,其中范围内的对象可能仍未被清除.在任何情况下,您可以帮助解释为什么以下结束OutOfMemoryError

public static void main(String[] args) {
    List<A> collect = null;
    int i=0;
    while(true){
        System.out.println(i++);
        collect = IntStream.range(0, 10_00_000).mapToObj(x -> new A(x + "")).collect(Collectors.toList());
    }
}

class A{
    String temp;
    A(String a){
        this.temp = a;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我把finalizeA用打印语句,它永远不会打印.实例OOME在几次迭代后结束.为什么不gc清除以前创建的collect.并且迭代次数也不是恒定的,范围从3偶数到100最终都是失败的-Xmx500m

其次为了好玩,我运行了上面的程序,禁用了JIT -Djava.compiler=NONE.它按预期永久运行.JIT如何影响它?

PS:当In包含System.gc();my my子句时,它会按预期运行.

Hol*_*ger 8

我无法重现您的结果-Xmx500m,但有-Xmx200m.一致地,添加finalize()方法时程序将失败,因为终结器是问题的原因.但是,一些"finalized"消息在我的系统打印.如果没有这种finalize()方法,它将永远运行完好(实际上直到我杀死它).

回收普通对象的空间没有问题,但是当您添加一个非常重要的finalize()方法时,您正在积极地阻止对象超出范围,因为它们现在必须排队以进行最终化.

虽然JVM将始终执行垃圾收集,尝试释放所有未使用的对象,但在抛出之前OutOfMemoryError,对于挂在终结队列中的对象没有这样的保证.通过禁用JIT来减慢主要任务可能确实允许最终化处理更多元素.请记住,主要任务和最终方法打印System.out都具有同步效果,这可能使处理的时间变得至关重要.

有几个环境因素会影响结果.由于没有关于哪个线程将执行终结器的保证,因此最终化可以使用所有未使用的CPU核心(并且您的主线程仅使用一个).实际的垃圾收集算法(JVM允许选择几种不同算法中的一种)也会产生影响.