finalize()分析
PS : 本文乃學習整理參考而來 。
生存還是死亡:
即使在可達性分析算法中不可達的對象,也并非是“非死不可”的,這時候他們暫時處于“緩刑”階段。要真正确定一個對象死亡,至少要經理兩次标記過程:如果對象在進行可達性分析後發現沒有與GC Roots相連接配接的引用鍊,那它将會被第一次标記并且進行一次篩選,篩選的條件是此對象是否有必要執行finalize()方法。當對象沒有覆寫finalize()方法,或者finalize()方法已經被虛拟機調用過,則虛拟機将這兩種情況都視為“沒有必要執行”。如果這個對象被判定為有必要執行finalize()方法,那麼這個對象将會放置在一個叫做F-Queue的隊列中,并在稍後由一個虛拟機自動建立的、低優先級的Finalizer線程去執行它。這裡所謂的“執行”是指虛拟機會觸發這個方法,但并不會承諾會等待它運作結束,這樣做的原因是如果一個對象在finalize()方法中執行緩慢或者發生了死循環,将可能會導緻F-Queue隊列中其他對象永久處于等待,甚至導緻整個記憶體回收系統崩潰。finalize()方法時對象逃脫死亡命運的最後一次機會,稍後GC将對F-Queue中的對象進行第二次小規模标記,如果對象要在finalize()中成功拯救自己——隻要重新與引用鍊上的任何一個對象建立關聯關系即可,那在第二次标記時他将被移除出“即将回收”的集合;如果這時候還沒有逃脫,那基本上就真的被回收了。以下是finalized()案例:
public class A{
public static A SAVE_HOOK = null;
public void isAlive(){
System.out.println("i am alive!);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("excuting finalize method!");
SAVE_HOOK = this;
}
public static void main(String[] args){
SAVE_HOOK = new A();
//對象第一次成功拯救自己
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();
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no , i am dead!")
}
}
}
輸出結果: excuting finalize method!
i am alive!
no , i am dead!
從代碼中可以看出SAVE_HOOK對象的finalize()方法确實被GC收集器觸發過并且被收集前成果逃脫了。另外需要注意的是代碼中有兩段一樣的片段,執行結果卻隻成功了一次,這是因為finalize()方法會被系統自動調用一次,如果面對已經執行過的對象進行新一次回收,他的finalize()方法不會再次被執行。書者建議盡量避免使用。