一次对象的自我拯救

2019-07-27  本文已影响0人  HAPPYers

分析

要真正回收掉一个对象,至少要经过两次标记过程。具体过程可以见JVM垃圾回收的分析文章。
如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖(重写)finalize()方法或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况视为"没有必要执行"。

下面的代码演示了如何通过覆盖finalize()防止对象自己被第一次垃圾回收。
GC的时候,第一次调用finalize(),又由于在finalize()方法中,将自己的对象引用this传给了静态变量SAVE_HOOK,所以第一次没有被回收。但是finalize()方法只会被调用一次,第二次,当SAVE_HOOK再次NULL的时候,该对象就被回收了。

代码

public class FinalizeEscapeGC {
    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("Now, I am alive!");
    }

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

    public static void main(String[] args) throws InterruptedException {
        SAVE_HOOK = new FinalizeEscapeGC();
        SAVE_HOOK = null;
        System.gc();
        // finalize方法的优先级很低,此处暂停0.5s来等待它
        Thread.sleep(500);
        if (SAVE_HOOK!=null){
            SAVE_HOOK.isAlive();
        }else{
            System.out.println("Ops, i am dead");
        }
        SAVE_HOOK=null;
        System.gc();
        Thread.sleep(500);
        if (SAVE_HOOK!=null){
            SAVE_HOOK.isAlive();
        }else{
            System.out.println("Ops, i am dead");
        }
    }
}

运行结果

Finalize method executed!
Now, I am alive!
Ops, i am dead
上一篇 下一篇

猜你喜欢

热点阅读