淺析finalize方法

昨天有個小夥伴聊到java對象finalize方法。因而就想好好總結一下。java

我們都知道判斷一個對象是否已經死了的方法有兩種:程序員

1:引用計數法算法

2:可達性分析算法app

因爲咱們一般使用的虛擬機使用的可達性分析算法,因此咱們這裏聊的都是可達性分析算法的相關。ide

判斷一個對象時生存仍是死亡???函數

即便在可達性分析算法中不可導的對象,也並不是就是‘非死不可’的,這時候咱們能夠理解爲改對象暫時處於「緩刑」階段,跟死囚犯同樣,仍是有機會不被砍頭的。this

 

說明一個對象已經死亡,至少須要經歷兩個被標記過程:spa

 

若是對象在進行可達性分析後發現沒有與GC Roots相鏈接的引用鏈,那它將會被第一次標記而且進行一次篩選,篩選的條件是此對象是否有必要執行finalize()方法。當對象沒有覆蓋finalize()方法,或者finalize()方法已經被虛擬機調用過,虛擬機將這兩種狀況都視爲「沒有必要執行」。線程

 

若是這個對象被斷定爲有必要執行finalize()方法,那麼這個對象將會放置在一個叫作orm

F-Queue的隊列之中,並在稍後由一個由虛擬機自動創建的、低優先級的Finalizer線程去執行它。這裏所謂的「執行」是指虛擬機會觸發這個方法,但並不承諾會等待它運行結束,這樣作的緣由是,若是一個對象在finalize()方法中執行緩慢,或者發生了死循環(更極端的狀況),將極可能會致使F-Queue隊列中其餘對象永久處於等待,甚至致使整個內存回收系統崩潰。finalize()方法是對象逃脫死亡命運的最後一次機會,稍後GC將對F-Queue中的對象進行第二次小規模的標記,若是對象要在finalize()中成功拯救本身——只要從新與引用鏈上的任何一個對象創建關聯便可,譬如把本身(this關鍵字)賦值給某個類變量或者對象的成員變量,那在第二次標記時它將被移除出「即將回收」的集合;若是對象這時候尚未逃脫,那基本上它就真的被回收了

 

Finalize方法具備如下四個特色:

  1. 永遠不要主動調用某個對象的finalize方法,該方法應該交給垃圾回收機制調用。

  2. Finalize方法合適被調用,是否被調用具備不肯定性,不要把finalize方法當作必定會執行的方法,

  3. 當JVM執行課恢復對象的finalize方法時,多是改對象或系統中其餘對象從新變成可達狀態

  4. 當JVM調用finalize方法出現異常時,垃圾回收機制不會報告異常,程序繼續執行。

 


注意點:

因爲finalize方法不必定被執行,那麼咱們想清理某各種裏打開的資源時,則不要方法finalize方法中。


實例說明:


運行結果能夠看出,SAVE_HOOK對象的finalize()方法確實被GC收集器觸發過,而且在被收集前成功逃脫了。另一個值得注意的地方是,代碼中有兩段徹底同樣的代碼片斷,執行結果倒是一次逃脫成功,一次失敗,這是由於任何一個對象的finalize()方法都只會被系統自動調用一次,若是對象面臨下一次回收,它的finalize()方法不會被再次執行,所以第二段代碼的自救行動失敗了。

須要特別說明的是,上面關於對象死亡時finalize()方法的描述可能帶有悲情的藝術色

彩,筆者並不鼓勵你們使用這種方法來拯救對象。相反,筆者建議你們儘可能避免使用它,由於它不是C/C++中的析構函數,而是Java剛誕生時爲了使C/C++程序員更容易接受它所作出的一個妥協。它的運行代價高昂,不肯定性大,沒法保證各個對象的調用順序。有些教材中描述它適合作「關閉外部資源」之類的工做,這徹底是對這個方法用途的一種自我安慰。finalize()能作的全部工做,使用try-finally或者其餘方式均可以作得更好、更及時,因此筆者建議你們徹底能夠

忘掉Java語言中有這個finalize方法的存在。

相關文章
相關標籤/搜索