1、概述
Java语言提供了对象终止(finalization)机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。
当垃圾回收器发现没有引用指向一个对象,即:垃圾回收此对象之前,总会先调用这个对象的finalize()方法。
finalize()方法允许在子类中被重写,用于在对象被回收时进行资源释放。通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件、套接字和数据库连接等。
从功能上来说,finalize()方法与C++中的析构函数比较相似,但是Java采用的是基于垃圾回收器的自动内存管理机制,所以finalize()方法在本质上不同于C++中的析构函数。
2、机制
对象的三种状态
由于finalize()方法的存在,虚拟机中的对象一般处于三种可能的状态。
如果从所有的根节点都无法访问到某个对象,说明对象己经不再使用了。一般来说,此对象需要被回收。但事实上,也并非是"非死不可"的,这时候它们暂时处于"缓刑"阶段。一个无法触及的对象有可能在某一个条件下"复活"自己,如果这样,那么对它的回收就是不合理的,为此,定义虚拟机中的对象可能的三种状态。需要注意的是只有在对象不可触及时才可以被回收。具体三种状态如下:
可触及的 - 从根节点开始,可以到达这个对象。
可复活的 - 对象的所有引用都被释放,但是对象有可能在finalize()中复活。
不可触及的 - 对象的finalize()被调用,并且没有复活,那么就会进入不可触及状态。不可触及的对象不可能被复活,因为finalize()只会被调用一次。
3、对象标记为垃圾的具体过程
判定一个对象objA是否可回收,要经历两次标(finalize())记或一次标记
1)如果对象objA到GC Roots没有引用链,则进行第一次标记。
2)进行筛选,判断此对象是否有必要执行finalize()方法
如果对象objA没有重写finalize()方法,或者finalize()方法已经被虚拟机调用过,则虚拟机视为"没有必要执行",objA被判定为不可触及的。
如果对象objA重写了finalize()方法,且还未执行过,那么objA会被插入到F-Queue队列中,由一个虚拟机自动创建的、低优先级的Finalizer线程触发其finalize()方法执行。
finalize()方法是对象逃脱死亡的最后机会,稍后GC会对F-Queue队列中的对象进行第二次标记。如果objA在finalize()方法中与引用链上的任何一个对象建立了联系,那么在第二次标记时,objA会被移出“即将回收”集合。之后,对象会再次出现没有引用存在的情况。在这个情况下,finalize方法不会被再次调用,对象会直接变成不可触及的状态,也就是说,一个对象的finalize方法只会被调用一次。
4、注意事项
永远不要主动调用某个对象的finalize(), 该方法应该交给垃圾回收机制调用
finalize()何时被调用不确定,不要把finalize()方法当成一定会执行的方法。
当JVM执行可恢复对象的finalize()时,可能使该对象或其他对象重新变回可达状态。
当JVM执行finalize方法出现异常时,垃圾回收机制不会报告异常,程序继续执行。