Garbage Collection -- 02 -- finalize()方法的作用

之前提到在可达性分析算法中,引用链不可达的对象将会被回收,不过这些对象并不是一定会被回收,可能会被 finalize() 方法赋予一次重生的机会 (仅有一次,因为一个对象的 finalize() 方法最多只会被系统自动调用一次)

要真正宣告一个对象死亡,至少要经历两次标记过程

  • 第一次标记

    • 如果对象在进行可达性分析算法后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件为此对象是否有必要执行 finalize() 方法,没有必要执行的情况如下

      • 对象没有覆盖 finalize() 方法

      • finalize() 方法已经被虚拟机调用过

  • 第二次标记

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

    • 虚拟机会触发这个方法,但并不承诺会等待它运行结束,也就是说可能 finalize() 方法还没有执行完毕,程序就已经执行完毕了

    • GC 将对 F-Queue 中的对象进行第二次小规模的标记

对象如何拯救自己

  • 对象需要在 finalize() 方法中重新与引用链上的任何一个对象建立关系,那么在第二次标记中,该对象将会被移除出 “即将回收” 的集合

  • 例如:将自己 (this 关键字) 赋值给某个类变量或者对象的成员变量


一、对象自我拯救示例

public class Finalization {
    
    private static Finalization finalization;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("Finalized");
        finalization = this;
    }

    public static void main(String[] args) {
        Finalization f = new Finalization();
        System.out.println("First print:" + f);
        f = null;
        System.gc();
        System.out.println("Second print:" + f);
        System.out.println(f.finalization);
    }
}

// 输出结果
// First print:jvm.gc.Finalization@262f6be5
// Second print:null
// Finalized
// null
  • 如上所示,我们先创建了一个 Finalization 对象,将其引用地址赋值给变量 f,接着将 f 置为 null,然后调用 GC,GC 会去执行对象的 finalize() 方法,并且会将 f 之前保存的引用地址赋值给类静态变量 finalization

  • 由输出结果可知,finalization = this 这句代码没有被执行,说明 finalize() 方法只执行了第一行代码,之后就被中止了,因为虚拟机并不承诺会等待 finalize() 方法运行结束

public class Finalization {
    
    private static Finalization finalization;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("Finalized");
        finalization = this;
    }

    public static void main(String[] args) {
        Finalization f = new Finalization();
        System.out.println("First print:" + f);
        f = null;
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Second print:" + f);
        System.out.println(finalization);
    }
}

// 输出结果
// First print:jvm.gc.Finalization@f0d1e0b
// Finalized
// Second print:null
// jvm.gc.Finalization@f0d1e0b
  • 若上所示,在调用 GC 后,让主线程休眠了 1 秒,让垃圾回收线程能够执行完成,最终得到了我们预期的输出结果,最后输出的与最先输出的是同一个实例,也就证明了 finalize() 这个方法能够为对象创造最后一次重生的机会

二、归纳总结

  • finalize() 方法的作用

    • 给予对象最后一次重生的机会
发布了106 篇原创文章 · 获赞 83 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Goodbye_Youth/article/details/105399049
今日推荐