1. 程式人生 > >JVM - 一次物件的自我拯救過程

JVM - 一次物件的自我拯救過程

故事:

在噼裡啪啦星球,有這樣一個原始部落,該部落民風淳樸。但也是有著嚴厲的法令去約束他們的行為。比如法令中有這樣一條:死刑。考慮到該刑法過於嚴重,所以該法令有個特權,緩刑執行,允許犯人緩刑執行期間自救,但是自救的行為每個人一生只有一次。假如某個人已經使用過自救的特權,那麼再次被判了死刑的話會被立即處決。初犯死刑的人員如果在自救期間能夠找到證據證明自己的清白,那麼他就會被豁免死刑,從而繼續存活,如果沒找到還是會被執行死刑。(該故事由《深入Java虛擬機器》章節3.2.4 “緩刑”一詞聯想而來,契合了一次物件的自我拯救過程,所以拿來作為引子,但也有些區別,這裡還請讀者自行理解,如有不當還請指出)

在經過可達性分析演算法判定某個物件為不可達時(犯了死刑),該物件也並非是“非死不可”的,這時候他們暫時處於“緩刑”階段,要真正宣告一個物件死亡,至少要經過兩次標記的過程(緩刑):如果物件在進行可達性分析後發現沒有與GC Roots 相連線的引用鏈,那他會被第一次標記並且進行一次篩選,篩選的條件是此物件是否有必要執行finalize()方法(這裡檢查是否已使用過自救的特權)。當物件沒有覆蓋finalize()方法或者finalize()方法已經被虛擬機器呼叫過(沒有自救的特權必死。喝了這碗酒,你安心上路,你老婆我來照顧→_→),虛擬機器將這兩種情況都視為“沒有必要執行”。

如果這個物件被判定有必要執行finalize()方法時(初犯死刑,還有自救特權

),那麼對將這個物件放置在一個叫做F-Queue的佇列中,並在稍後由一個虛擬機器自動建立的、低優先順序的Finalizer執行緒去執行。finalize()方法是物件逃脫死亡命運的最後一次機會,稍後GC將對F-Queue中的物件進行第二次小規模標記,如果物件要在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()方法只會被系統自動呼叫一次。