简体   繁体   English

Object 参考的 scope 过期后的垃圾收集

[英]Object garbage collection after reference's scope expires

Firstly let me say I am aware that System.gc() is more of a suggestion to collect garbage than a command, and that collection is not guaranteed to finish, start, or collect a specific object.首先让我说我知道 System.gc() 更像是一个收集垃圾的建议而不是一个命令,并且不能保证收集完成、启动或收集特定的 object。 And yet...但是...

With the following code, the a1 instance only gets collected if I explicitly put null in the reference.使用下面的代码,只有当我明确地将 null 放在参考中时,才会收集 a1 实例。 If a1 simply goes out of scope, it does not get collected.如果 a1 只是从 scope 出去,它不会被收集。

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);
    }
}

Why does a1 not get collected if it simply goes out of scope, when there are no strong references to it?如果没有强引用,为什么 a1 只是从 scope 出去时不会被收集? Is it because this scope does not constitute a separate stack frame?是不是因为这个scope不构成单独的栈帧?

It's totally up to the JVM to decide when a1 gets collected or whether the finalizer runs.完全由 JVM 决定何时收集a1或终结器是否运行。

For instance, a JVM might decide to run this in an interpreter which simply has a local variable table that holds every local variable in the method - similarly to how this works in the byte code - and variables don't really go 'out of scope' from the GC's perspective until the method exits.例如,JVM 可能决定在解释器中运行它,该解释器仅具有一个局部变量表,该表保存方法中的每个局部变量——类似于字节码中的工作方式——并且变量并不是真正的 go '超出范围' 从 GC 的角度来看,直到方法退出。

But, for instance, a JIT compiler could be more aggressive with limiting the GC scope of locals (or rather, it simply doesn't keep track of what it doesn't need to).但是,例如,JIT 编译器可能会更积极地限制本地人的 GC scope(或者更确切地说,它根本不跟踪它不需要的东西)。 So, if you for instance run the program with -Xcomp (on the HotSpot JVM) which forces this code to be JIT compiled, you might (or might not) see the output:因此,如果您使用-Xcomp (在 HotSpot JVM 上)运行程序,强制此代码进行 JIT 编译,您可能(或可能不会)看到 output:

Finally executed
Collecting A

Without setting a1 to null explicitly.没有明确地将a1设置为null

On the other hand, if you were to run this with Epsilon GC (which is a no-op GC) using the VM options: -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC (again on HotSpot), you might not see Collecting A in the output at all, even if you explicitly set a1 to null .另一方面,如果您使用 Epsilon GC(这是一个无操作 GC)使用 VM 选项运行它: -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC (再次在 HotSpot 上),您可能看不到Collecting A在 output 中,即使您明确地将a1设置为null

So, yeah, it's really up to the VM.所以,是的,这真的取决于虚拟机。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM