引用范围过期后的对象垃圾回收



首先让我说,我知道System.gc((更像是一个收集垃圾的建议,而不是一个命令,并且收集不能保证完成、启动或收集特定对象。然而。。。

对于下面的代码,只有当我在引用中显式地放置null时,a1实例才会被收集。如果a1只是超出了范围,它就不会被收集。

class A {
@Override
protected void finalize() throws Throwable {
System.out.println("Collecting A");
}
}
public class Example {
public static void main(String[] args) throws InterruptedException {
try {
A a1 = new A();
//a1 = null; // a1 gets collected only if I uncomment this line
}
finally {
System.out.println("Finally executed");
}
System.gc();
Thread.sleep(1000);
}
}

如果a1超出了范围,而没有强有力的引用,为什么它不被收集?是因为这个范围不构成一个单独的堆栈框架吗?

完全由JVM决定何时收集a1或是否运行终结器。

例如,JVM可能会决定在解释器中运行它,解释器只需要有一个本地变量表来保存方法中的每个本地变量——类似于字节码中的工作方式——并且在方法退出之前,从GC的角度来看,变量不会真正"超出范围"。

但是,例如,JIT编译器可以更积极地限制本地的GC范围(或者更确切地说,它根本不跟踪不需要跟踪的内容(。因此,例如,如果您使用-Xcomp(在HotSpot JVM上(运行程序,强制对该代码进行JIT编译,您可能会(也可能不会(看到输出:

Finally executed
Collecting A

而不显式地将a1设置为null

另一方面,如果您使用Epsilon GC(这是一个非操作GC(使用VM选项-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC(同样在HotSpot上(运行此程序,则即使您将a1显式设置为null,您也可能根本看不到输出中的Collecting A

所以,是的,这真的取决于虚拟机。

最新更新