GC 不清除范围内的对象
GC not clearing objects in scope
我很久以前看过一篇文章,但我似乎没有找到它。它解释了以下行为,其中范围内的对象可能仍未被清除。无论如何,您能否帮助解释为什么以下内容以 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;
}
}
当我用打印语句将 finalize
放入 A
时,它永远不会被打印出来。并且实例在几次迭代后以 OOME
结束。为什么 gc
不清除以前创建的 collect
。而且迭代次数也不是恒定的,它 运行 从 3
到甚至 100
但最终失败 -Xmx500m
其次,为了好玩,我 运行 上面的程序禁用了 JIT -Djava.compiler=NONE
。它会按预期永远运行。 JIT 如何影响它?
PS:当 In 在我的 while 子句中包含 System.gc();
时,它会按预期保持 运行。
我无法用 -Xmx500m
重现你的结果,但用 -Xmx200m
重现你的结果。一致地,当您添加 finalize()
方法时程序将失败,因为终结器是问题的 原因 。然而, 一些 "finalized"
消息打印在我的系统中。没有 finalize()
方法,它会永远完美运行(好吧,实际上直到我杀死它)。
回收普通对象的 space 没有问题,但是当您添加一个重要的 finalize()
方法时,您正在主动防止对象超出范围,因为它们现在必须排队等候完成。
虽然 JVM 将始终执行垃圾收集,尝试释放所有未使用的对象,然后再抛出 OutOfMemoryError
,但对于挂在终结队列中的对象没有这样的保证。通过禁用 JIT 来减慢主要任务可能确实允许终结处理更多元素。请记住,主任务和最终方法都打印到 System.out
具有同步效果,这会使处理时间变得至关重要。
有几个环境因素会影响结果。由于无法保证哪个线程将执行终结器,因此终结器可以使用所有未使用的 CPU 核心(并且您的主线程仅使用一个)。
实际的垃圾收集算法(JVM 允许选择几种不同算法中的一种)也会产生影响。
我很久以前看过一篇文章,但我似乎没有找到它。它解释了以下行为,其中范围内的对象可能仍未被清除。无论如何,您能否帮助解释为什么以下内容以 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;
}
}
当我用打印语句将 finalize
放入 A
时,它永远不会被打印出来。并且实例在几次迭代后以 OOME
结束。为什么 gc
不清除以前创建的 collect
。而且迭代次数也不是恒定的,它 运行 从 3
到甚至 100
但最终失败 -Xmx500m
其次,为了好玩,我 运行 上面的程序禁用了 JIT -Djava.compiler=NONE
。它会按预期永远运行。 JIT 如何影响它?
PS:当 In 在我的 while 子句中包含 System.gc();
时,它会按预期保持 运行。
我无法用 -Xmx500m
重现你的结果,但用 -Xmx200m
重现你的结果。一致地,当您添加 finalize()
方法时程序将失败,因为终结器是问题的 原因 。然而, 一些 "finalized"
消息打印在我的系统中。没有 finalize()
方法,它会永远完美运行(好吧,实际上直到我杀死它)。
回收普通对象的 space 没有问题,但是当您添加一个重要的 finalize()
方法时,您正在主动防止对象超出范围,因为它们现在必须排队等候完成。
虽然 JVM 将始终执行垃圾收集,尝试释放所有未使用的对象,然后再抛出 OutOfMemoryError
,但对于挂在终结队列中的对象没有这样的保证。通过禁用 JIT 来减慢主要任务可能确实允许终结处理更多元素。请记住,主任务和最终方法都打印到 System.out
具有同步效果,这会使处理时间变得至关重要。
有几个环境因素会影响结果。由于无法保证哪个线程将执行终结器,因此终结器可以使用所有未使用的 CPU 核心(并且您的主线程仅使用一个)。 实际的垃圾收集算法(JVM 允许选择几种不同算法中的一种)也会产生影响。