谈谈你对 finalize 方法的理解,该怎样回答才能体现出高水平?浮于表面的答案永远不行!

目录

1. finalize 方法是什么?

2. finalize 方法的作用?

3. 为什么强烈不建议在 finalize 方法中进行资源的释放和清理工作


1. finalize 方法是什么?

首先要知道,finalize 方法是 Object 类中的一个方法,从源码中叶可儿一看到,所以所有的对象都会具有这个方法,该方法修饰符为 protected ,子类可以进行 @Override 重写,但实际开发过程中一般不会去理会它。

在 JDK9 之后,该方法已经被官方不推荐使用了,但面试的时候还是有可能会被问到的,所以我们就来聊聊该方法的一些作用。

2. finalize 方法的作用?

finalize 方法是在对象被垃圾回收器回收之前执行的,当我们将一个对象设置为 null 之后,它就变成了垃圾,等待着垃圾回收器回收,finalize 方法主要就是做一些清理善后的工作,如果一个对象重写了 finalize 方法,那么它在被垃圾回收器回收之前,就会先执行 finalize 方法。

由此也带来了它的另一个作用,通常一个对象都是具有很多的功能属性的,所以我们就可以将一些资源的释放;例如文件关闭操作,网络连接断开操作放到 finalize 方法中去完成。

如下代码所示

public class Test {
    // 重写 Test 类中的 finalize() 方法
    @Override
    public void finalize() throws Throwable{
        // 打印一句话作为标记,证明该方法被调用过
        System.out.println("finalize方法执行");
    }
    public static void main(String[] args) throws Exception {
        // 创建类对象 t
        Test t = new Test();
// 获取该对象
        System.out.println(t+"第一次获取对象");
// 将对象t赋值为 null,此时堆中的对象就会变成垃圾
        t = null;
        // 手动开启垃圾回收GC,将垃圾回收,验证 finalize方法是否执行
        System.gc();
        // 因为GC垃圾回收是另外的垃圾回收线程,所以我们让主线程先睡两秒,避免造成误差
        Thread.sleep(2000);
        // 经过GC之后再次获取t对象
        System.out.println(t+"第二次获取对象");
    }
}

这里还有一点需要提醒注意,Java虚拟机的GC是单独的GC垃圾回收线程,并且该线程是 main 线程的守护线程,只要 main 线程运行结束,GC垃圾回收线程就会停止,所以在代码中我才让 main 线程调用 sleep 方法。

然后我们运行上述方法,在控制台中得到如下所示结果

可以看到,将对象 t 赋值为 null 之后,finalize 方法就执行了。

3. 为什么强烈不建议在 finalize 方法中进行资源的释放和清理工作

经过了上面的演示,现在已经得知,finalize 方法会在对象被垃圾回收器回收之前执行此方法,但是!!!强烈不建议在 finalize 方法中进行资源的释放和清理工作。

原因我总结了以下三点

(1)资源释放实际成谜。

如果我们重写了 finalize 方法,那么对象在变成垃圾被垃圾回收器回收之前,需要先执行 finalize 方法,而 finalize 方法并不是由垃圾回收器来调用的,是有一个专门的线程叫 finalizer 来调用的,finalizer 线程内部有一个引用队列,垃圾回收器识别到垃圾对象之后,会把该对象添加到引用队列中去,finalizer 线程会依次调用每个对象的 finalize 方法然后进行清理。如果说一个对象不再被任何一个变量引用,我们就希望它能够马上被回收释放占用的系统资源,但是垃圾回收算法的运行时机是不确定的,而且缺少对该垃圾对象的监控,所以我们无从得知盖拉几何时会被清理掉,资源的释放时机就成了谜。

(2)资源释放异常,对象变成"僵尸"。

finalize 既然是一个方法,那么它就有可能抛出异常,如果抛出异常,垃圾清理到一半又没有清理完,此时这个对象就不能被清除掉,就变成半死不活的"僵尸"了,一直占用系统资源无法被释放。

(3)很容易导致OOM(内存溢出)

GC垃圾回收线程和主程序的线程不是同一个线程。也就是说,我们的主线程,也可以说是业务一直都在持续地进行着,那么业务就很有可能会在内存中继续创建出新的对象进行其他的业务操作。而此时先前创建的对象被回收需要调用 finalize 方法,如果我们将一些资源的释放工作和内存清理工作全部放到 finalize 方法中的话,是非常耗时的,特别是网络断开连接操作,需要等待对方的响应才能断开连接,但现在内存中的垃圾对象又需要等待 finalize 方法执行完毕后才能清除,由于业务的不断进行,还有不断新的对象被创建,垃圾对象的清理速度慢,新对象的创建速度快,清理的速度没有创建的速度快,一定会造成内存溢出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值