前边一篇文章详述了JVM判定对象何时需要进行回收,但是即使前边所说的算法判定对象该回收之后,他也并非是“非死不可”的,这时他暂时处于“缓刑”阶段,真正的宣告标记对象死亡至少要经历两次标记过程:如果对象没有任何与“GC Roots”相连的链,它将会被第一次标记,并且进行一次筛选,筛选的条件是对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法或者finalize()方法已经被虚拟机调用过,这两种情况将被视为“没有必要执行”。
如果这个对象被判定为有必要执行finalize()方法,那么这个对象会被放在一个叫做F-Queue的队列中,并稍后由一个由虚拟机建立的、低优先级的Finalizer线程去执行它。这里的执行并不保证会等待它运行结束,因为如果一个对象的finalize()方法执行缓慢,或者发生了死循环,很可能导致F-Queue队列中的其他对象处于等待,甚至导致整个内存回收系统的崩溃。finalize()方法是对象拯救自己的最后一次机会——只需要重新与引用链上的对象建立关联即可。
请看如下代码:
package test;
public class TTTT {
public static TTTT SAVE_HOOK = null;
public static void isAlive(){
if(SAVE_HOOK != null)
System.out.println("Yes,I am alive :)");
else
System.out.println("No,I am dead :(");
}
@Override
protected void finalize() throws Throwable{
super.finalize();
System.out.println("finalize method excuted!");
SAVE_HOOK = this;
}
public static void main(String[] args) throws Throwable {
SAVE_HOOK = new TTTT();
SAVE_HOOK = null;
System.gc();
Thread.sleep(1);
isAlive();
SAVE_HOOK = null;
System.gc();
Thread.sleep(1);
isAlive();
}
}
执行结果如下:
这是因为,finalize()方法只会被虚拟机调用一次,因此第一次拯救成功,第二次却拯救失败。