在进行过可达性分析后的对象也不一定是非死不可的,该对象进行可达性分析后,发现没有与GC Roots相连接的引用链,
- .这个对象就会第一次被标记起来;对对象是否必要执行finalize函数进行判断;(已经被GC调用过finalize方法或者没有重写finalize方法都认为是没有必要执行该finalize函数的)
- F-Queue队列中存放该对象,优先级较低的Finalizer会去执行它;Gc 会对这个队列里面的对象再进行一次标记,如果在finalize方法中,对象没有自己自救的话,它就会被标记回收
- finalize方法自救自己的办法是:重新与引用链上面的任何一个对象建立连接,或者把自己this赋值给某个类或对象的成员变量
/**
1.对象可以在GC时自救
2.自救的办法只有一次,因为一个finalize方法最多只能被调用一次
**/
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive(){
System.out.println("yes,I am still alive :)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed !");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String [] args) throws InterruptedException {
SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次成功拯救自己
SAVE_HOOK = null;
System.gc();
//因为finalize优先级很低,所以延迟0.5s以等待它;
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no, i am dead :(");
}
//下面这段代码再执行一遍,验证对象是不是可以成功
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no, i am dead :(");
}
}
}
结果如下:
finalize method executed !
yes,I am still alive :)
no, i am dead :(
- 并不鼓励使用这种办法来拯救对象,它的运行代价高昂,不确定性大,无法保证顺序;
- finalize方法能做的所有工作,try-finally也可以做的更好,更及时,所以希望忘记这个方法的存在;