基础
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。