JVM - 一次物件的自我拯救過程
阿新 • • 發佈:2018-11-17
故事:
在噼裡啪啦星球,有這樣一個原始部落,該部落民風淳樸。但也是有著嚴厲的法令去約束他們的行為。比如法令中有這樣一條:死刑。考慮到該刑法過於嚴重,所以該法令有個特權,緩刑執行,允許犯人緩刑執行期間自救,但是自救的行為每個人一生只有一次。假如某個人已經使用過自救的特權,那麼再次被判了死刑的話會被立即處決。初犯死刑的人員如果在自救期間能夠找到證據證明自己的清白,那麼他就會被豁免死刑,從而繼續存活,如果沒找到還是會被執行死刑。(該故事由《深入Java虛擬機器》章節3.2.4 “緩刑”一詞聯想而來,契合了一次物件的自我拯救過程,所以拿來作為引子,但也有些區別,這裡還請讀者自行理解,如有不當還請指出)
在經過可達性分析演算法判定某個物件為不可達時(犯了死刑),該物件也並非是“非死不可”的,這時候他們暫時處於“緩刑”階段,要真正宣告一個物件死亡,至少要經過兩次標記的過程(緩刑):如果物件在進行可達性分析後發現沒有與GC Roots 相連線的引用鏈,那他會被第一次標記並且進行一次篩選,篩選的條件是此物件是否有必要執行finalize()方法(這裡檢查是否已使用過自救的特權)。當物件沒有覆蓋finalize()方法或者finalize()方法已經被虛擬機器呼叫過(沒有自救的特權必死。喝了這碗酒,你安心上路,你老婆我來照顧→_→),虛擬機器將這兩種情況都視為“沒有必要執行”。
如果這個物件被判定有必要執行finalize()方法時(初犯死刑,還有自救特權
書中程式碼示例,這裡直接粘過來的
/** * 此程式碼演示了兩點: 1. 物件可以在被 GC 時自我拯救 * 2. 這種自救的機會只有一次,因為一個物件的finalize()方法只會被系統自動呼叫一次 * * @author cyl */ 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.5 秒等待他 Thread.sleep(500); if (SAVE_HOOK != null) { SAVE_HOOK.isAlive(); } else { System.out.println("yes, i am still alive :("); } /***************************************/ // 下面的程式碼與上面的完全相同,但是這次自救卻失敗了 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 :("); } } } /**執行結果 * finalize method executed! * yes, i am still alive :) * no, i am dead :( */
PS:任何一個物件的finalize()方法只會被系統自動呼叫一次。