java - Java中通过finalize()函数测试垃圾回收,是活的还是死的?

标签 java garbage-collection jvm

正如您在进入 if 分支之前的第一个 block SAVE_HOOK = null; 中看到的,我认为 SAVE_HOOK == null,所以它不应该进入 SAVE_HOOK.isAlive();。但实际上,我在 Eclipse 中测试了它:

面向 Java 开发人员的 Eclipse IDE

版本:Neon.3 版本 (4.6.3)

内部版本号:20170314-1500

为什么会发生这种情况?

public class FinalizeEscapeGC {

    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("yes, i am still alive :)");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();

        // ---------------block 1----------------//
        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if (SAVE_HOOK != null) {    // "SAVE_HOOK = null;"
            SAVE_HOOK.isAlive();    //  why the frist time it can go inside this if branch? 
        } else {
            System.out.println("no, i am dead :(");
        }
        // ---------------block 1----------------//

        // the same as the above block
        // ---------------block 2----------------//
        SAVE_HOOK = null;
        System.gc();        
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no, i am dead :(");
        }
        // ---------------block 2----------------//
    }
}
<小时/>

结果:

最终执行方法!

是的,我还活着:)

不,我死了:(

最佳答案

听起来您想问两个问题:

  1. 为什么第一个 block 之后 SAVE_HOOK 不为 null?
  2. 为什么在第二个相同的 block 之后它为空?

第一个问题的简单答案是:因为System.gc()触发了垃圾收集器,垃圾收集器又运行了终结器,它显式地重新分配了引用。但我假设您已经知道这一点,您想问的是:为什么在终结器完成后没有回收对象?

答案在 finalize() 的文档中:

After the finalize method has been invoked for an object, no further action is taken until the Java virtual machine has again determined that there is no longer any means by which this object can be accessed [...] at which point the object may be discarded.

因此,只要您仍然拥有对该对象的强引用,它就永远不会被垃圾回收。

第二个问题的答案是:您将其设置为 null 并且永远不会重新分配它,因为特定实例的终结器只会运行一次。这也在文档中,就在上一个引用之后:

The finalize method is never invoked more than once by a Java virtual machine for any given object.

关于java - Java中通过finalize()函数测试垃圾回收,是活的还是死的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43795427/

相关文章:

Java Android Spinner onItemSelected

Java 垃圾收集器 A 类 -> B 类 -> C 类 -> B 类和循环引用

memory-leaks - 禁用D的GC是 'ok'吗?

android - Eclipse:我无法在 Ubuntu 11.10 上调试我的应用程序

java - Spring Batch/集成入站 channel 适配器

java - 准备好的语句 executeUpdate 不适用于更新语句

java - 在 Java 中创建日期的正确方法是什么?

php - session 结束时运行脚本

java - Java中替换字符串的内存高效方法

java - 使用 javac 和 javax.tools.JavaCompiler 有什么区别?