JVM—finalize方法

作者: 兔子胡萝卜抱 | 来源:发表于2018-05-03 19:46 被阅读0次

    一、Finalize方法的过程

    一个对象真正宣告死亡,至少要经历两次标记过程:如果对象在进行可达性分析之后发现没有与GC Roots相连接的引用链,那它将被第一次标记并且进行一次筛选。筛选的条件是此对象是否有必要执行finalize()方法。


    当遇到以下两种情况时,虚拟机将视为“没有必要执行”:
    1.对象是否覆盖finalize()方法
    2.finalize()方法已经被虚拟机调用过


    如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个F-Queue的队列中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程执行。

    注:这里的“执行”指的是虚拟机有机会触发这个方法,但并不承诺会等待它运行结束。因为一个对象在finalize()方法中执行是非常缓慢的,甚至有可能会发生死循环,将会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。

    finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象在finalize()方法中拯救自己(重新与引用链上任何一个对象建立关联),那么在第二次标记时它将被移除“即将回收”的集合,如果对象这时候还没有逃脱,那基本上就真的被回收了~~~(gg

    对象回收过程中触发finalize()方法

    二、一次对象的自我拯救代码清单

    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 method executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }
    
    public static void main(String[] args) throws Throwable {
        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("no,I am dead :(");
        }
    
        //第二次拯救失败
        SAVE_HOOK = null;
        System.gc();
        //因为finalize方法优先级很低,所以暂停0.5s等待
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,I am dead :(");
        }
    }}
    

    运行结果:

    finalize method executed!
    
    yes,I am still alive :)
    
    no,I am dead :(
    

    从代码清单中可知,SAVE_HOOK对象的finalize()方法确实被GC收集器触发过,并且在被收集前成功逃脱了。

    另外,在完全一样的两端代码片段里,第二次的执行结果确实逃脱失败了。这是因为任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法就不会被再次执行。

    最后,在JVM中并不鼓励使用finalize()对象来拯救对象。因此它的运行代码非常高昂而且不确定性大。finalize()方法能做的工作,使用try-finally或者其他方式都可以做的更好更及时。

    相关文章

      网友评论

        本文标题:JVM—finalize方法

        本文链接:https://www.haomeiwen.com/subject/fpvlrftx.html