深入理解java的finalize
目錄?
基本預(yù)備相關(guān)知識(shí)?
對(duì)象的銷毀過程?
對(duì)象重生的例子?
對(duì)象的finalize的執(zhí)行順序?
何時(shí)及如何使用finalize?
參考?
基本預(yù)備相關(guān)知識(shí)?
1?java的GC只負(fù)責(zé)內(nèi)存相關(guān)的清理,所有其它資源的清理必須由程序員手工完成。要不然會(huì)引起資源泄露,有可能導(dǎo)致程序崩潰。?
2 調(diào)用GC并不保證GC實(shí)際執(zhí)行。?
3 finalize拋出的未捕獲異常只會(huì)導(dǎo)致該對(duì)象的finalize執(zhí)行退出。?
4 用戶可以自己調(diào)用對(duì)象的finalize方法,但是這種調(diào)用是正常的方法調(diào)用,和對(duì)象的銷毀過程無關(guān)。?
5 JVM保證在一個(gè)對(duì)象所占用的內(nèi)存被回收之前,如果它實(shí)現(xiàn)了finalize方法,則該方法一定會(huì)被調(diào)用。Object的默認(rèn)finalize什么都不做,為了效率,GC可以認(rèn)為一個(gè)什么都不做的finalize不存在。?
6 對(duì)象的finalize調(diào)用鏈和clone調(diào)用鏈一樣,必須手工構(gòu)造。?
如?
Java代碼??
對(duì)象的銷毀過程?
在對(duì)象的銷毀過程中,按照對(duì)象的finalize的執(zhí)行情況,可以分為以下幾種,系統(tǒng)會(huì)記錄對(duì)象的對(duì)應(yīng)狀態(tài):?
unfinalized 沒有執(zhí)行finalize,系統(tǒng)也不準(zhǔn)備執(zhí)行。?
finalizable 可以執(zhí)行finalize了,系統(tǒng)會(huì)在隨后的某個(gè)時(shí)間執(zhí)行finalize。?
finalized 該對(duì)象的finalize已經(jīng)被執(zhí)行了。?
GC怎么來保持對(duì)finalizable的對(duì)象的追蹤呢。GC有一個(gè)Queue,叫做F-Queue,所有對(duì)象在變?yōu)閒inalizable的時(shí)候會(huì)加入到該Queue,然后等待GC執(zhí)行它的finalize方法。?
這時(shí)我們引入了對(duì)對(duì)象的另外一種記錄分類,系統(tǒng)可以檢查到一個(gè)對(duì)象屬于哪一種。?
reachable 從活動(dòng)的對(duì)象引用鏈可以到達(dá)的對(duì)象。包括所有線程當(dāng)前棧的局部變量,所有的靜態(tài)變量等等。?
finalizer-reachable 除了reachable外,從F-Queue可以通過引用到達(dá)的對(duì)象。?
unreachable 其它的對(duì)象。?
來看看對(duì)象的狀態(tài)轉(zhuǎn)換圖。?
好大,好暈,慢慢看。?
1 首先,所有的對(duì)象都是從Reachable+Unfinalized走向死亡之路的。?
2 當(dāng)從當(dāng)前活動(dòng)集到對(duì)象不可達(dá)時(shí),對(duì)象可以從Reachable狀態(tài)變到F-Reachable或者Unreachable狀態(tài)。?
3 當(dāng)對(duì)象為非Reachable+Unfinalized時(shí),GC會(huì)把它移入F-Queue,狀態(tài)變?yōu)镕-Reachable+Finalizable。?
4 好了,關(guān)鍵的來了,任何時(shí)候,GC都可以從F-Queue中拿到一個(gè)Finalizable的對(duì)象,標(biāo)記它為Finalized,然后執(zhí)行它的finalize方法,由于該對(duì)象在這個(gè)線程中又可達(dá)了,于是該對(duì)象變成Reachable了(并且Finalized)。而finalize方法執(zhí)行時(shí),又有可能把其它的F-Reachable的對(duì)象變?yōu)橐粋€(gè)Reachable的,這個(gè)叫做對(duì)象再生。?
5 當(dāng)一個(gè)對(duì)象在Unreachable+Unfinalized時(shí),如果該對(duì)象使用的是默認(rèn)的Object的finalize,或者雖然重寫了,但是新的實(shí)現(xiàn)什么也不干。為了性能,GC可以把該對(duì)象之間變到Reclaimed狀態(tài)直接銷毀,而不用加入到F-Queue等待GC做進(jìn)一步處理。?
6 從狀態(tài)圖看出,不管怎么折騰,任意一個(gè)對(duì)象的finalize只至多執(zhí)行一次,一旦對(duì)象變?yōu)镕inalized,就怎么也不會(huì)在回到F-Queue去了。當(dāng)然沒有機(jī)會(huì)再執(zhí)行finalize了。?
7 當(dāng)對(duì)象處于Unreachable+Finalized時(shí),該對(duì)象離真正的死亡不遠(yuǎn)了。GC可以安全的回收該對(duì)象的內(nèi)存了。進(jìn)入Reclaimed。?
對(duì)象重生的例子?
Java代碼??
期待輸出?
Java代碼??
但是有可能失敗,源于GC的不確定性以及時(shí)序問題,多跑幾次應(yīng)該可以有成功的。詳細(xì)解釋見文末的參考文檔。?
對(duì)象的finalize的執(zhí)行順序?
所有finalizable的對(duì)象的finalize的執(zhí)行是不確定的,既不確定由哪個(gè)線程執(zhí)行,也不確定執(zhí)行的順序。?
考慮以下情況就明白為什么了,實(shí)例a,b,c是一組相互循環(huán)引用的finalizable對(duì)象。?
何時(shí)及如何使用finalize?
從以上的分析得出,以下結(jié)論。?
1 最重要的,盡量不要用finalize,太復(fù)雜了,還是讓系統(tǒng)照管比較好。可以定義其它的方法來釋放非內(nèi)存資源。?
2 如果用,盡量簡(jiǎn)單。?
3 如果用,避免對(duì)象再生,這個(gè)是自己給自己找麻煩。?
4 可以用來保護(hù)非內(nèi)存資源被釋放。即使我們定義了其它的方法來釋放非內(nèi)存資源,但是其它人未必會(huì)調(diào)用該方法來釋放。在finalize里面可以檢查一下,如果沒有釋放就釋放好了,晚釋放總比不釋放好。?
5 即使對(duì)象的finalize已經(jīng)運(yùn)行了,不能保證該對(duì)象被銷毀。要實(shí)現(xiàn)一些保證對(duì)象徹底被銷毀時(shí)的動(dòng)作,只能依賴于java.lang.ref里面的類和GC交互了。?
參考?
關(guān)于引用類型,GC,finalize的相互交互可以參考ReferenceQueue GC finalize Reference 測(cè)試及相關(guān)問題
總結(jié)
以上是生活随笔為你收集整理的深入理解java的finalize的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 群晖使用Docker搭建蚂蚁笔记
- 下一篇: 创建一个在若干工具上交易的 EA 交易程