java为什么不推荐覆写Object的finalize方法

Posted wen-pan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java为什么不推荐覆写Object的finalize方法相关的知识,希望对你有一定的参考价值。

说明:

  • 在JVM中除了强、软、弱、虚这四种引用以外,其实还有一种类型的引用,这种引用非常不常见,在日常开发中基本99.9999999999%不会用,在JVM回收覆写了finalize方法的对象时会用到这种引用。这种引用就是【终结器引用】。
  • java提供了一个finalize方法,可以帮助我们进行资源释放,类似于C++中的析构函数。但是目前普遍的认识是不要使用,为什么呢?就是因为对java虚拟机的垃圾回收有影响。

1、为什么不推荐使用覆写Object的finalize方法

Object类的finalize方法被重写时,希望在这个对象被垃圾回收的时候调用这个finalize方法来完成一些资源释放或其他操作,但这是非常不可取的。为什么?看下面流程分析!

2、finalize回收流程

假设A对象覆写了finalize方法

  • 在A对象在初始化的过程中会判断是否重写了finalize方法,方法是判断两个字段标志has_finalizer_flagRegisterFinalizersAtInit
  • 在第一次垃圾回收时,GC垃圾收集器发现没有强引用 引用A对象时,并且A对象覆写了finalize方法。所以此时即使A对象已经没有任何强引用了垃圾收集器也不能立刻回收他。而是由JVM虚拟机为A对象创建一个【终结器引用对象】
  • 并且将这个【终结器引用对象】加入到引用队列ReferenceQueue
  • 这时A对象还没有被垃圾回收
  • 再由一个优先级很低的线程(finalizeHandler),去查看引用队列ReferenceQueue中是否有新加入的元素
    • 如果有,则从队列中取出这个【终结器引用对象】并由这个【终结器引用对象】找到A对象,并且调用他的finalize()方法,等finalize方法调用完了,这个对象就可以被垃圾收集器回收了。

3、原因总结

可以发现,finalize方法工作效率很低,有以下几点

  • 第一点:第一次垃圾回收时,即使这个对象已经没有了任何强引用,垃圾回收器也不能回收他,而是为他创建一个终结器对象并加入到队列
  • 第二点:处理队列中的【终结器引用对象】的线程优先级很低,很难被CPU执行到,进而导致对象的finalize方法迟迟不能被执行,资源迟迟不能被释放,对象迟迟不能被垃圾回收
  • 第三点:覆写finalize方法有可能会造成垃圾对象复活

4、覆写finalize方法造成对象复活分析

①、代码案例

@Data
public class Student {
    String name;
    int age;

    /**
     * 覆写finalize
     */
    @Override
    protected void finalize() throws Throwable {
        // 在finalize方法中使得当前对象再次被引用(这就是对象复活)
        Classroom.student = this;
    }
}

@Data
public class Classroom {

  	// 静态变量
    public static Student student;

}

②、案例分析

  • 上面代码中Student类覆写了finalize方法,当student对象没有任何强引用后,便会被垃圾收集器标记为垃圾(但不能立刻回收,需要执行完finalize方法才能回收)
  • 当JVM线程执行student对象的finalize方法的时候,在该方法中该对象被静态变量重新引用Classroom.student
  • 所以当再次GC的时候,会发现本来已经是垃圾的student对象现在突然不是垃圾了(复活了)

5、参考

https://www.cnblogs.com/manayi/p/14651133.html

https://blog.csdn.net/weixin_39843151/article/details/110618282

以上是关于java为什么不推荐覆写Object的finalize方法的主要内容,如果未能解决你的问题,请参考以下文章

java 覆写Object.equals() 方法

11.JAVA-Object类之finalize(),clone(),toString()等方法覆写

Java中关于equals()和hashCode()的问题

为什么不建议使用自定义Object作为HashMap的key?

Java中三种常见的注释(注解) Annotation

在Java中的重载和覆写