詳解java中finalize的實現(xiàn)與相應(yīng)的執(zhí)行過程
FinalReference引用
此類是一個package類型,表示它并不是公開的一部分,繼承自Reference, 即表示也是一種特定的引用類型,因此每個包裝在其中的對象在被回收之前,自己都會放到指定的referqyebceQueue當(dāng)中.
這個引用對象專門為帶finalize方法的類服務(wù),可以理解為每一個有相應(yīng)的方法的對象,其都會封裝為一種finalRefernece對象.
因為finalize方法是object定義的,其默認(rèn)實現(xiàn)為空.那么如果重寫了此方法,那么方法體肯定不為空.即可以通過這一種區(qū)別來.只要finalize方法實現(xiàn)不為空的類,此產(chǎn)生的對象都需要被注冊到finalRefernece中.
這一步可以通過在newInstance的時候,即調(diào)用object默認(rèn)構(gòu)造方法的時候,就可以進(jìn)行相應(yīng)的注冊了.
Finalizer#register方法
主要調(diào)用了此方法,就會產(chǎn)生相應(yīng)的finalizer對象,而finalizer對象是繼承于finalReference的.此方法聲明如下:
/* Invoked by VM */ static void register(Object finalizee) { new Finalizer(finalizee); }
從上面注釋可以看出,此方法會被jvm在特定時期調(diào)用.
然后切換到Finalizer的構(gòu)造方法,如下所示:
private Finalizer(Object finalizee) { super(finalizee, queue); add(); }
可以看出,相應(yīng)的引用對象會通過queue進(jìn)行回調(diào).add的作用在于將所有還未進(jìn)行finalize方法的對象存起來,在最后System.shutdown
時調(diào)用.通過Runtime#runFinalizersOnExit
進(jìn)行設(shè)置.
ReferenceQueue
此引用隊列會在相應(yīng)reference對象的內(nèi)部對象被回收之前放到此隊列中(詳細(xì)說明在另一篇關(guān)于reference中再說明.),因為只需要從此隊列中拿到相應(yīng)的對象,那么此對象就肯定是準(zhǔn)備被回收的.
那么在回收之前調(diào)用相應(yīng)的finalize方法即可.
FinalizerThread線程
此線程即是從queue里面,不停的獲取數(shù)據(jù),然后調(diào)用相應(yīng)的finalize方法.相應(yīng)的代碼如下所示:
for (;;) { try { Finalizer f = (Finalizer)queue.remove(); f.runFinalizer(jla); } catch (InterruptedException x) { // ignore and continue } }
而相應(yīng)的runFinalizer如下所示:
synchronized (this) { if (hasBeenFinalized()) return; remove(); } try { Object finalizee = this.get(); if (finalizee != null && !(finalizee instanceof java.lang.Enum)) { jla.invokeFinalize(finalizee); /* Clear stack slot containing this variable, to decrease the chances of false retention with a conservative GC */ finalizee = null; } } catch (Throwable x) { } super.clear();
在上面的邏輯當(dāng)中,首先調(diào)用remove將其從未finalize中移除.這個方法是保證每個對象的finalize最多只會被調(diào)用一次,即當(dāng)前這次調(diào)用完了.它就會被記相應(yīng)的狀態(tài),即hasBeenFinalized返回為true(其實就是把里面的next指針指向自己.即自己從未finalize中移除,同時也不需要再次調(diào)用finalize了).
接下來就是調(diào)用相應(yīng)的finalize方法,上面的jla.invokeFinalize
其實就是調(diào)用相應(yīng)對象的finalize方法. 在這個處理中,首先通過get獲取原始對象.在整個jvm處理中,針對finalizeReference在回收之前默認(rèn)是不將引用設(shè)置為null.因為這里,總是能夠獲取相應(yīng)的引用對象.
處理完之后,最后調(diào)用相應(yīng)的clear,清除相應(yīng)的引用.這樣達(dá)到最終引用沒有其它對象可引用的效果.
在上面的處理當(dāng)中,并沒有限定調(diào)用finalize的時間.因此,一旦如果某個對象的finalize調(diào)用慢,就會影響到整個回收鏈的執(zhí)行,這下就會產(chǎn)生相應(yīng)的OOM異常了.因此,除非特殊情況,就不要重寫finalize,相應(yīng)的場景都應(yīng)該有其它方法可以處理.比如guava中的FinalizableReference.
finalizer啟動線程
在上面的線程,在相應(yīng)的進(jìn)程啟動過程中就會被啟動.可以理解為,對象通過調(diào)用register(object)
觸發(fā)finalizer類的初始化.然后,在靜態(tài)初始化塊當(dāng)中,就會啟動相應(yīng)的回收線程.相應(yīng)的初始化代碼如下所示:
static { ThreadGroup tg = Thread.currentThread().getThreadGroup(); for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()); Thread finalizer = new FinalizerThread(tg); finalizer.setPriority(Thread.MAX_PRIORITY - 2); finalizer.setDaemon(true); finalizer.start(); }
上面的static是靜態(tài)初始化塊,即只要類Finalizer被使用,即會觸發(fā)相應(yīng)的調(diào)用.這里使用的線程組是系統(tǒng)線程組,優(yōu)先級也還算高,被配置為后臺線程.
在使用jstack打印線程時,出現(xiàn)的如圖下所示的線程,即是由這里來啟動的.如下圖所示
總結(jié)
整個Finalizer即是通過finalReference,由JVM和相應(yīng)的java類相互配合來協(xié)同工作.并不是全部由jvm實現(xiàn),因此可以認(rèn)為其也并不是太底層的東西,而是為了實現(xiàn)相應(yīng)的語義.一切都是正常的java來完成,由jvm配合.了解到整個過程,也是對java本身的運行機制有所了解.
相關(guān)文章
Java toString方法重寫工具之ToStringBuilder案例詳解
這篇文章主要介紹了Java toString方法重寫工具之ToStringBuilder案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08SpringMvc請求處理參數(shù)?和?響應(yīng)數(shù)據(jù)處理的示例詳解
這篇文章主要介紹了SpringMvc請求處理參數(shù)和響應(yīng)數(shù)據(jù)處理,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-09-09spring boot 自定義規(guī)則訪問獲取內(nèi)部或者外部靜態(tài)資源圖片的方法
這篇文章主要介紹了spring boot 自定義規(guī)則訪問獲取內(nèi)部或者外部靜態(tài)資源圖片的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01SpringCloud中NacosNamingService的作用詳解
這篇文章主要介紹了SpringCloud中NacosNamingService的作用詳解,NacosNamingService類完成服務(wù)實例注冊,撤銷與獲取服務(wù)實例操作,NacosNamingService初始化采用單例模式,使用反射生成,需要的朋友可以參考下2023-11-11Java 配置log4j日志文件路徑 (附-獲取當(dāng)前類路徑的多種操作)
這篇文章主要介紹了Java 配置log4j日志文件路徑 (附-獲取當(dāng)前類路徑的多種操作),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10Java泛型枚舉Annotation接口詳細(xì)解讀與Eclipse發(fā)展
這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08spring boot-2.1.16整合swagger-2.9.2 含yml配置文件的代碼詳解
這篇文章主要介紹了spring boot-2.1.16整合swagger-2.9.2 含yml配置文件,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08