Object.finalize()
简介
官方注释
Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the {@code finalize} method to dispose of system resources or to perform other cleanup.
译文:当垃圾回收确定不再有对该对象的引用时,由垃圾回收器在对象上调用。 子类覆盖{@code finalize}方法以处置系统资源或执行其他清理。
当对象不可达时(GC Roots), GC会判断对象是否覆盖了finalize()
:
- 若未覆盖则直接将其回收。
- 若对象覆盖并且未执行过(手动调用的不计此列)
finalize()
, 将其放入F-Queue
队列,由一个低优先级线程执行该队列中对象的finalize()
方法。执行finalize()
完毕后, Gc会再次判断该对象是否可达:- 若不可达, 则进行回收。
- 可达, 对象“复活”。
原理
即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段。要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()
方法。当对象没有覆盖finalize()
方法,或者finalize()
方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。
如果这个对象被判定为有必要执行finalize()
方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()
方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。
finalize()
方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()
中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。
对象生命流程
对象可由两种状态组成, 涉及到两类状态空间:
- 终结状态空间:F = {
unfinalized, finalizable, finalized
}; -
可达状态空间:R = {
reachable, F(finalizer)-reachable, unreachable
}。 - unfinalized: 新建对象会先进入此状态,GC并未准备执行其finalize方法,该对象可达的;
- finalizable: GC已检测到该对象不可达,GC通过
F-Queue
队列和专用线程完成finalize的执行; - finalized: GC已经对该对象执行过finalize方法;
- reachable:GC Roots引用可达;
- finalizer-reachable:不是reachable,但可通过某个finalizable对象可达;
- unreachable:不可达,没有被任何对象引用;
- 新建对象处于
reachable
,unfinalized
(A)状态; - 随着程序的运行,一些引用关系会消失,导致状态变迁,从
reachable
状态变迁到f-reachable
(B, C, D)或unreachable
(E, F)状态; - 若JVM检测到处于
unfinalized
状态的对象变成f-reachable
或unreachable
,JVM会将其标记为finalizable
(G,H)状态,若对象原处于[unreachable
,unfinalized
]状态,则同时将其标记为f-reachable
(H); - 在某个时刻,JVM取出某个
finalizable
对象,将其标记为finalized
并在某个线程中执行其finalize()。由于是在活动线程中引用了该对象,该对象将变迁到(reachable
,finalized
)(K或J)状态,该动作将影响某些其他对象从f-reachable
状态重新回到reachable
(L, M, N)状态; - 处于
finalizable
状态的对象不能同时是unreahable
的,由第4点可知,将对象finalizable
对象标记为finalized
时会由某个线程执行该对象的finalize(),致使其变成reachable
; - 程序员手动调用finalize()并不会影响到上述内部标记的变化,因此JVM只会至多调用finalize()一次,即使该对象“复活”也是如此。
- JVM检测到
finalized
状态的对象变成unreachable
,回收其内存(I); - 若对象并未覆盖finalize(),JVM会进行优化,直接回收对象(O);
System.runFinalizersOnExit()
等方法可以使对象即使处于reachable
状态,JVM仍对其执行finalize方法;