上篇文章講到,虛擬機器判斷一個物件是否可回收是根據“可達性分析”,不可達的物件就是可回收的物件,但是被判定為“不可達的物件”也並非“非死不可”。它們只是被判了“緩刑”,最後是死是生都有可能。
我們看看回收無效物件的過程:
-
物件經過可達性分析後,發現沒有被
GC Roots
關聯,則會被第一次標記。 -
判斷物件是否覆蓋了finalize方法。
如果覆蓋了該方法,並且該物件的finalize
方法還沒有執行過。則將這個物件放到F-Queue
佇列中,稍後虛擬機器將啟動一個優先順序比較低的Finalizer執行緒去執行finalize方法。
如果沒有覆蓋該方法,或者說finalize
方法已經執行過了,則物件就只能等死(等待垃圾收集器將其回收)
- 執行F-Queue佇列中等待執行的finalize方法
Finalizer執行緒執行F-Queue
佇列中的finalize
方法時,將是物件自救的最後一次機會。如果方法的執行使得物件被其他變數或物件所引用,則GC Roots
變為可達,GC將會把它移出“即將回收”的物件集合。如果它沒有自救,那它就只能等待回收了。
- 回收“即將回收”的集合中的所有物件
垃圾回收器將基於其採用的回收演算法,對無用物件進行回收。
說說finalize方法
從上面的過程中,可以看出,一個類如果定義了finalize
方法,在垃圾回收其例項的過程,會先執行finalize
方法。
那麼,是不是意味著我們可以再finalize
方法中進行資源釋放呢?
這樣做是很危險的。因為在執行F-Queue
佇列中的finalize
方法時,虛擬機器並不承諾完整地執行完整個方法。因為如果finalize
方法中執行的操作比較耗時,虛擬機器將終止它以保證佇列中其他finalize
方法能夠及時執行。
因此,釋放資源還是選擇try - finally
的方式吧。
另外,物件自救的方法也不建議利用finalize方法,因為finalize只會被系統呼叫一次,物件可能活過第一次,但是卻可能活不過第二次的垃圾回收,因為第二次時finalize將不再執行。
總之,finalize方法瞭解就好,實際情況中不建議使用。
點贊是對我最大的鼓勵