Java对象的finalization机制

Java中的对象终止机制通过finalize()方法实现,允许在对象被垃圾回收前执行自定义清理逻辑。垃圾回收器在确定对象不可触及后会调用finalize(),但调用时机不确定且只会调用一次。对象可能经历可触及、可复活和不可触及三个状态,只有不可触及状态的对象才会被回收。测试代码展示了如何通过finalize()复活对象,但复活后不会再次调用finalize()。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • Java语言提供了对象终止(finalization)机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。

  • 当垃圾回收器发现没有引用指向一个对象,即:垃圾回收此对象之前,总会先调用这个对象的finalize() 方法。

  • finalize() 允许子类中被重写,用于对象被回收时进行资源释放。通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件,套接字和数据库连接等。

  • Object类的方法

protected void finalize() throws Throwable { }
  • 永远不要调用某个对象的finalize()方法。应该交给垃圾回收器调用,理由如下:
  • 在finalize()时对象可能复活
  • finalize()的执行时间是没有保障的,它完全由GC线程决定,极端情况下,如果永远不发生GC,那么finalize()方法永远不会被执行。
  • 一个糟糕的finalize()会严重影响GC执行。
  • 从功能上说,finalize()方法和c++的析构函数比较类似,但Java采用的是基于垃圾回收的自动管理机制,所以本质上不同于c++的析构函数。
  • 由于finalize()的存在,虚拟机中对象一般处于三种状态。

如果所有的根节点无法访问到某个对象,说明该对象已经不再使用。一般来说此对象需要被回收。但事实上也并非是“非死不可”的,这时候他们暂时处于缓刑阶段。一个无法触及的对象可能在某一个条件下复活自己,如果那样,那么对它的回收就是不合理的,为此虚拟机中的对象有以下三个状态:

  • 可触及的:从根节点可以达到的对象
  • 可复活的:对象的多有引用都被释放,但是对象可能在finalize()中复活。
  • 不可触及的:对象finalize()被调用,并且没有复活,那么就会进入不可触及状态。不可触及的对象不可复活,因为finalize()只会被调用一次。
  • 以上三种状态中,是由于finalize()存在进行的区分,只有对象是不可及状态才会被回收。

  • 判定一个对象是否可以回收至少要经过两次标记。

1:如果对象A到GC Roots没有引用链,则进行第一次标记。
2:进行筛选,判断此对象是否有必要执行finalize()方法。
(1)如果对象A没有重写finalize()方法,或者finalize()方法已经被虚拟机调用过,则虚拟机视为没有必要执行,A被视为不可执行的。
(2)如果对象A重写了finalize()方法,且还未执行过,那么A会被插入到F-Queue队列中,由一个虚拟机自动创建的,低优先级的Finalizer线程触发其finalize()方法执行。
(3)finalize()方法是对象逃脱死亡的最后方法,稍后GC会对F-Queue队列中的对象进行二次标记,如果A在finalize()中与引用链上的任何一个对象建立了联系,那么在二次标记时, A会被移出即将回收集合。之后,对象会再次出现没有引用的情况,在这个情况下finalize()不会被再次调用,对象会直接变为不可触及对象。也就是说finalize()只会被调用一次。

  • 下面代码测试了 finalize机制的调用,复活对象,但finalize只能调用一次
public class ExampleUnitTest {

    public static ExampleUnitTest instance;

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("调用了finalize()方法...");
        // 如果不将instance和外部连接起来,那么第一次GC就已经为null了
        instance = this;
    }

    @Test
    public void addition_isCorrect() {
        instance = new ExampleUnitTest();

        instance = null;
        System.gc();
        try {
            // 延迟为了保证GC能进行
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (instance != null) {
            System.out.println("instance 还活着...");
        } else {
            System.out.println("instance 死了...");
        }

        instance = null;
        System.gc();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (instance != null) {
            System.out.println("instance 还活着...");
        } else {
            System.out.println("instance 死了...");
        }

    }
}

打印结果如下:

调用了finalize()方法...
instance 还活着...
instance 死了...

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值