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

时间:2017-05-05 02:15:47

标签: java garbage-collection jvm

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

中测试了它

Eclipse IDE for Java Developers

版本:Neon.3发布(4.6.3)

构建ID: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----------------//
    }
}

结果:

敲定mehtod执行!

是的,我还活着。)

不,我死了:(

3 个答案:

答案 0 :(得分:1)

归结为:对象只能在其生命周期内完成一次。 finalize方法可以使对象第一次转义删除,但下次对象被检测为无法访问,它将被删除。

答案 1 :(得分:1)

听起来你正试图提出两个问题:

  1. 为什么SAVE_HOOK在第一个阻止后不为空?
  2. 为什么在第二个相同的块之后它为空?
  3. 第一个问题的简单答案是:因为System.gc()触发了垃圾收集器,垃圾收集器又运行了终结器,它明确地重新分配了引用。但我猜你已经知道了,你的意思是:为什么在终结者完成后没有回收对象?

    答案在finalize()的文档中:

      

    在为对象调用finalize方法之后,在Java虚拟机再次确定不再有任何方法可以访问此对象之前,不会采取进一步操作[...]此时可以丢弃该对象。

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

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

      

    对于任何给定对象,Java虚拟机永远不会多次调用finalize方法。

答案 2 :(得分:0)

在对象的生命周期中,它将经历可达 - > finalizable-> finalized->回收阶段。在执行finalize()方法之后,对象将进入最终阶段,并等待下一个gc触发器,它将被回收。所以在生命周期中,finalize()方法只会被激活一次。您的SAVE_HOOK是一个静态变量,它再次在finalize()方法中赋值。这就是为什么在第一个if块中,它不是空的。但第二次,它已经死了。