图解JVM 对象是否存活 (三) finalize方法

解析

一. finalize的作用

  • finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。
  • finalize()与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性
  • 不建议用finalize方法完成“非内存资源”的清理工作,但建议用于:
    • ① 清理本地对象(通过JNI创建的对象);
    • ② 作为确保某些非内存资源(如Socket、文件等)释放的一个补充:在finalize方法中显式调用其他资源释放方法。

二. finalize的生命周期

当对象变成不可达时, GC会判断该对象是否已经覆盖过finalize方法, 如果没有覆盖, 则直接回收, 否则, 若对象未执行过finalize方法, 将其放入F-Queue队列, 由一低优先级线程执行该队列对象中的finalize方法. 执行完毕后, GC会再次判断可达性(即只有一次自救的机会), 若不可达, 则直接进行回收, 否则对象**“复活”**.

图解


生命周期解释

  1. 新建对象首先处于[reachable, unfinalized] 状态 (A)
  2. 随着程序运行, 一些引用关系会消失, 从reachable状态迁移到f-unreachable 或 unreachable状态.
  3. 若JVM检测到处于unfinalized状态的对象变成f-reachable或unreachable, JVM会标记为fianlizable状态(G H), 也就是可以进行finalize方法的状态
  4. 在某个时刻, JVM取出某个finalizable对象, 标记为finalized并在某个线程中执行该对象的finalize方法.
  5. 处于finalizable状态的对象不能同时为unreachable, 因为finalizable对象标记为finalized时, 某个线程会执行该对象的finalize方法, 使其变成reachable.
  6. 手动调用finalize方法对于状态转换是无效的(不影响JVM的行为).
  7. 若JVM检测到finalized状态的对象变成不可达(unreachable), 就回收其内存(I)
  8. 若对象并未覆盖finalize方法, JVM会对其优化, 直接回收对象(O)

实战代码

/**
 * 演示内容:
 * 1. 对象可以在被GC时自我拯救
 * 2. 这种自救的机会只有一次, 因为一个对象的finalize()方法最多被调用一次
 */
public class FinalizeEscapeGC {
    public static FinalizeEscapeGC SAVE_HOOK = null;

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("触发finalize方法...");
        // 进行拯救
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public void isAlive() {
        System.out.println("我复活了 ^ ^");
    }
    public static void main(String[] args) throws InterruptedException{
        SAVE_HOOK = new FinalizeEscapeGC();

        // 对象被GC回收前执行finalize方法, 可以有一次自我拯救的机会
        SAVE_HOOK = null;
        System.gc();

        // finalize方法优先级低(JVM会调用一个优先级低的线程执行Queue-F队列中的finalize方法)
        // 保证finalize方法已经执行完毕
        Thread.sleep(1000);

        if (null != SAVE_HOOK) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("我死了 TAT");
        }

        // 尝试再次自救
        SAVE_HOOK = null;
        System.gc();

        // 因为finalize()方法优先级很低, 保证执行
        Thread.sleep(1000);

        if (null != SAVE_HOOK) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("我死了 TAT");
        }
    }
}

实战结果

触发finalize方法...
我复活了 ^ ^
我死了 TAT

说明对象最多只能执行一次自救, 之后不会再调用finalize方法.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值