基础
Java技术允许使用finalize()
在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
这个方法是由垃圾收集器在确定这个对象没有被引用时,对这个对象调用的。它是在Object
类中定义的,因此所有的类都继承了它。子类覆盖finalize()
以整理系统资源或者执行其他清理工作(要不然会引起资源泄露,有可能导致程序崩溃)。finalize()
是在垃圾收集器删除对象之前被自动调用的。
垃圾收集器只知道释放那些由new
分配的内存,所以不知道如何释放对象的“特殊”内存。为解决这个问题,Java提供了一个名为finalize()
,它的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize()
,而且只有在下一次垃圾收集过程中,才会真正回收对象的内存(垃圾回收需要2次)。
所以如果使用finalize()
,就可以在垃圾收集期间进行一些重要的清除或清扫工作(如关闭流等操作)。但JVM(Java虚拟机)不保证此方法总被调用。
finalize()
抛出的未捕获异常只会导致该对象的finalize()
执行退出。
用户可以自己调用对象的finalize()
,但是这种调用是正常的方法调用,和对象的销毁过程无关。
对象销毁和对象重生
一个简单的对象生命周期为,Unfinalized
、Finalizable
、Finalized
、Reclaimed
。
在对象的销毁过程中,按照对象的finalize()
的执行情况,可以分为以下几种,系统会记录对象的对应状态。
unfinalized
没有执行finalize()
,系统也不准备执行。
finalizable
可以执行finalize()
了,系统会在随后的某个时间执行finalize
。
finalized
该对象的finalize()
已经被执行了。
GC怎么来保持对finalizable()
的对象的追踪呢。GC有一个Queue
,叫做F-Queue
,所有对象在变为finalizable
的时候会加入到该Queue
,然后等待GC执行它的finalize()
。
这时我们引入了对对象的另外一种记录分类,系统可以检查到一个对象属于哪一种:
reachable
从活动的对象引用链可以到达的对象。包括所有线程当前栈的局部变量,所有的静态变量等等。
finalizer-reachable
除了reachable
外,从F-Queue
可以通过引用到达的对象。
unreachable
其它的对象,不可达对象。

- 首先,所有的对象都是从
Reachable+Unfinalized
(没有执行finalize()
,对象可达)走向死亡之路的。
- 从当前活动集到对象不可达时,对象可以从
Reachable
状态变到F-Reachable
(进入F-Queue
,对象变成finalizable
状态)或者Unreachable
状态。
- 当对象为非
Reachable+Unfinalized
时,GC会把它移入F-Queue
,状态变为F-Reachable+Finalizable
(进入F-Queue
,可达,finalizable
状态)。
- 任何时候,GC都可以从
F-Queue
中拿到一个Finalizable
的对象,标记它为Finalized
,然后执行它的finalize()
,由于该对象在这个线程中又可达了,于是该对象变成Reachable
了(并且Finalized
)。而finalize()
执行时,又有可能把其它的F-Reachable
(进入F-Queue
,finalizable
状态)的对象变为一个Reachable
的,这个叫做对象再生。
- 当一个对象在
Unreachable+Unfinalized
时,如果该对象使用的是默认的Object
的finalize
,或者虽然重写了,但是新的实现什么也不干(子类覆写一个空方法)。为了性能,GC可以把该对象之间变到Reclaimed
状态直接销毁,而不用加入到F-Queue
等待GC做进一步处理。(不可达,不执行finalize()
)
- 从状态图看出,不管怎么折腾,任意一个对象的
finalize
只至多执行一次,一旦对象变为Finalized
(执行过finalized()
),就怎么也不会在回到F-Queue
(finalizable
状态)去了。当然没有机会再执行finalize
了。
- 当对象处于
Unreachable+Finalized
时,该对象离真正的死亡不远了。GC可以安全的回收该对象的内存了。进入Reclaimed
。