1. 程式人生 > >【Java虛擬機器】finalize() 方法

【Java虛擬機器】finalize() 方法

finalize() 方法

物件的回收需要經歷兩次標記過程:如果物件在進行可達性分析後發現沒有與GC Roots相連線的引用鏈,那麼它將會被第一次標記並且進行一次篩選,篩選的條件就是此物件是否有必要執行finalize() 方法。當物件沒有覆蓋finalize() 方法,或者finalize() 方法已經被虛擬機器呼叫過,虛擬機器將這兩種情況都視為“沒有必要執行”。

如果這個物件被判定為有必要執行finalize() 方法,那麼這個物件將會放置一個叫做F-Queue的佇列之中,並在稍後由一個虛擬機器自動建立的、低優先順序的Finalizer執行緒去執行它。finalize() 方法是物件逃脫被回收的最後一次機會,稍後GC將對F-Queue中的物件進行第二次小規模的標記,如果物件要在finalize() 方法中成功拯救自己——只要重新與引用鏈上的任何一個物件建立關聯即可,比如把自己賦值給某個類變數或者物件的成員變數,那麼第二次標記時它將被移除出“即將回收”的集合;如果物件這時候還沒有逃脫,那基本上它就真的被回收了。

舉個例子

public class FinalizeEscapeGC {
	public static FinalizeEscapeGC save_hook = null;

	public void isSave() {
		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(); Thread.sleep(500); if (save_hook != null) { save_hook.isSave(); } else { System.out.println("no, i am dead :("); } save_hook =
null; System.gc(); Thread.sleep(500); if (save_hook != null) { save_hook.isSave(); } else { System.out.println("no, i am dead :("); } } }

輸出結果為:

finalize method executed!
yes, i am still alive :)
no, i am dead :(

從輸出結果可以看出finalize() 方法被執行,第一次GC後它仍然可以存活,第二次GC後它被回收,這是因為finalize() 方法只會被系統自動呼叫一次。

參考

  1. 深入理解Java虛擬機器[書籍]