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

首先让我说我知道 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

没有明确设置a1null

另一方面,如果您要使用 VM 选项通过 Epsilon GC(这是一个无操作 GC)运行它:(-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC再次在 HotSpot 上),您可能根本看不到Collecting A输出,即使您明确设置a1null.

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

  • In principle, it’s also possible to see the output `Collecting A ␍ Finally executed`

以上是引用范围过期后的对象垃圾回收的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>