真正要宣告一个对象死亡,至少要经历两次标记:
1、 如果对象在进行可达性分析后发现没有与GC Root相连接的引用链,将会被第一次标记,并且进行一次筛选,筛选条件是对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法或finalize()方法已经被虚拟机调用过,虚拟机将这两种情况称为没有必要执行。
2、 如果对象被判定为有必要执行finalize()方法,那么该对象将会被放置到低优先级的Finalize线程去执行它,但不承若会等待它运行结束,GC将对F_Queue中的对象进行第二次小规模的标记,如果对象要在finalize()方法中成功解救自己,只要重新与引用链上的任何一个对象建立关联即可,如果对象这时候还没有逃脱那基本上它就真的被回收了。
/**
* 此代码演示了两点:
* 1、对象可以被GC是自我拯救
* 2、这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统调用一次
* @author xiaomage
*
*/
public class FinalizeEscapeGC {
private static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive(){
System.out.println("yes, i am still alive :)");
}
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method execute");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws InterruptedException {
SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次解救成功
SAVE_HOOK = null;
System.gc();
//因为finalize()方法优先级低,所以暂停0.5秒以等待它
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no , i am dead :(");
}
//下面的代码与上面的代码完全相同,但是这次自救却失败了
SAVE_HOOK = null;
System.gc();
//因为finalize()方法优先级低,所以暂停0.5秒以等待它
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no , i am dead :(");
}