Java学习笔记 (三十) finalize()方法

可达性分析算法中不可达的对象,并不是一定要回收的。真正判定一个不可达对象要回收,至少要经历两次标记过程。

第一次标记

如果对象在进行可达性分析之后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记并且进行一次筛选。
筛选的条件是此对象是否需要执行 finalize() 方法。当对象没有覆写 finalize() 方法,或者 finalize() 方法已经被虚拟机调用过,这两种情况都是不需要执行 finalize() 方法。
如果对象被判定为需要执行 finalize() 方法,这个对象就会被放在一个叫做 F-Queue 的队列之中,并在稍后由一个虚拟机自动建立的、低优先级的 Finalizer 线程去执行它。这里的执行是指虚拟机会触发这个方法,但不一定会等待它运行结束。这是因为如果一个对象在 finalize() 方法中执行缓慢,或者发生死循环,将可能导致 F-Queue 队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。

第二次标记

finalize() 方法是对象拯救自己的最后一次机会。
GC 会对 F-Queue 中的对象进行第二次标记,如果对象在finalize()方法中 将自己与引用链的任何一个对象建立关联, 那么在第二次标记时它将会被移出 即将回收的集合。否则将会被回收。

示例

如下,对象第一次成功拯救自己,第二次只能死亡。。。。

package finalize;

public class FinalizeEscapeGC {

    static FinalizeEscapeGC finalizeEscapeGC=null;



    @Override
    protected void finalize() throws Throwable {
        System.out.println("拯救自己...........................");
        //将自己与引用链关联起来
        finalizeEscapeGC=this;
    }

    public void isLive(String name){
        System.out.println(name+": 对象还活着.........");
    }

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

        //让对象可以被回收
        finalizeEscapeGC=null;

        System.gc();

        //finalize 方法优先级很低,所以暂停 0.5 秒以等待它
        Thread.sleep(500);

        if (finalizeEscapeGC==null){
            System.out.println("第一次 对象死了。。。。。。。。。");
        }else {
            finalizeEscapeGC.isLive("第一次 ");
        }


        //让对象可以被回收
        finalizeEscapeGC=null;

        System.gc();

        //finalize 方法优先级很低,所以暂停 0.5 秒以等待它
        Thread.sleep(500);

        if (finalizeEscapeGC==null){
            System.out.println("第二次 对象死了。。。。。。。。。");
        }else {
            finalizeEscapeGC.isLive("第二次 ");
        }


    }

}

执行结果输出如下:
在这里插入图片描述
可以看出,GC之后,finalize() 方法触发,与引用链关联,成功执行自己,第二次却没有触发 finalize() 方法。
这是因为任何一个对象的 finalize() 方法都只会被系统自动调用一次,第二次垃圾回收时 finalize() 方法将不会执行。

参考资料

学习摘抄于深入理解Java虚拟机

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章