垃圾回收之物件的死亡過程
當觸發垃圾回收時,GC(垃圾回收)執行緒會根據跟搜尋演算法判斷這個物件是否可達(即GCroot到這個物件之間時否有一條可達的引用鏈)。
如果可達,很幸運,你繼續活著。
如果不可達,當然你不一定百分之一百就死掉了,在殺死一個物件之前,GC執行緒至少會對這個物件標記兩次,
垃圾回收執行緒在對所有不可達的物件進行第一次標記後,會進行一個篩選,
篩選的條件是:是否執行這個物件的fianlize()方法。這個方法是Object物件自帶的,所以每個物件也都包含此方法。
如果 物件的fianlize()方法被這個物件覆蓋,或者這個物件的finalize()方法是否被虛擬機器呼叫過。
則則被判斷為很有必要呼叫物件的fianlize()方法。
如果被判斷有必要執行物件的fianlize()方法,那麼這個物件會被放入一個叫做F-Queue的佇列中,
稍後會有虛擬機器自動建立一個低優先順序的fianlizer的執行緒,此執行緒回去觸發佇列中物件的fianlize()方法,
但是不保證等待物件的finalize()方法執行結束,因為萬一物件的這個方法執行的非常緩慢,甚至極端的出現了死迴圈,
會影響F-Queue佇列中的其他物件的處理,甚至導致整個垃圾回收崩潰。
因為物件的finalize()方法會被呼叫,又可以被重寫,所以這是這些物件逃離昇天不被垃圾回收kill的唯一的一次機會。
如果這些物件重寫了自己的finalize()方法,並且順利的把自己重新複製給一個新的引用,
這樣的話就有了GCroot指向此物件,再第二次進行垃圾回收的時候就可以逃離昇天了。
如果再這個方法中沒有給自己找一個新的歸屬,就真的離死亡不遠了,GC執行緒的死亡之鐮會揮舞向你。
注意:請儘量不要複寫這個finalize(),用它來拯救物件,因為執行他的代價太大,不確定性也很大,物件的執行順序也不一樣。
至於用它來關閉資源,這只是一個自我安慰。try catch finally 效果更好也更容易把控。所以可以把這個方法完全忘記。
GCroot主要包括以下幾類:
1.虛擬機器棧(棧中的本地變量表)中引用的物件。
2.方法區中類靜態屬性引用的物件。
3.方法區中常量引用的物件。
4.本地方法棧中JNI(即常說的native方法中)引用的物件