国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

詳解java中finalize的實現與相應的執行過程

2019-11-26 13:50:49
字體:
來源:轉載
供稿:網友

FinalReference引用

此類是一個package類型,表示它并不是公開的一部分,繼承自Reference, 即表示也是一種特定的引用類型,因此每個包裝在其中的對象在被回收之前,自己都會放到指定的referqyebceQueue當中.

這個引用對象專門為帶finalize方法的類服務,可以理解為每一個有相應的方法的對象,其都會封裝為一種finalRefernece對象.

因為finalize方法是object定義的,其默認實現為空.那么如果重寫了此方法,那么方法體肯定不為空.即可以通過這一種區別來.只要finalize方法實現不為空的類,此產生的對象都需要被注冊到finalRefernece中.

這一步可以通過在newInstance的時候,即調用object默認構造方法的時候,就可以進行相應的注冊了.

Finalizer#register方法

主要調用了此方法,就會產生相應的finalizer對象,而finalizer對象是繼承于finalReference的.此方法聲明如下:

/* Invoked by VM */static void register(Object finalizee) { new Finalizer(finalizee);}

從上面注釋可以看出,此方法會被jvm在特定時期調用.
然后切換到Finalizer的構造方法,如下所示:

private Finalizer(Object finalizee) { super(finalizee, queue); add();}

可以看出,相應的引用對象會通過queue進行回調.add的作用在于將所有還未進行finalize方法的對象存起來,在最后System.shutdown時調用.通過Runtime#runFinalizersOnExit進行設置.

ReferenceQueue

此引用隊列會在相應reference對象的內部對象被回收之前放到此隊列中(詳細說明在另一篇關于reference中再說明.),因為只需要從此隊列中拿到相應的對象,那么此對象就肯定是準備被回收的.

那么在回收之前調用相應的finalize方法即可.

FinalizerThread線程

此線程即是從queue里面,不停的獲取數據,然后調用相應的finalize方法.相應的代碼如下所示:

for (;;) { try {  Finalizer f = (Finalizer)queue.remove();  f.runFinalizer(jla); } catch (InterruptedException x) {  // ignore and continue }}

而相應的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();

在上面的邏輯當中,首先調用remove將其從未finalize中移除.這個方法是保證每個對象的finalize最多只會被調用一次,即當前這次調用完了.它就會被記相應的狀態,即hasBeenFinalized返回為true(其實就是把里面的next指針指向自己.即自己從未finalize中移除,同時也不需要再次調用finalize了).

接下來就是調用相應的finalize方法,上面的jla.invokeFinalize其實就是調用相應對象的finalize方法. 在這個處理中,首先通過get獲取原始對象.在整個jvm處理中,針對finalizeReference在回收之前默認是不將引用設置為null.因為這里,總是能夠獲取相應的引用對象.

處理完之后,最后調用相應的clear,清除相應的引用.這樣達到最終引用沒有其它對象可引用的效果.

在上面的處理當中,并沒有限定調用finalize的時間.因此,一旦如果某個對象的finalize調用慢,就會影響到整個回收鏈的執行,這下就會產生相應的OOM異常了.因此,除非特殊情況,就不要重寫finalize,相應的場景都應該有其它方法可以處理.比如guava中的FinalizableReference.

finalizer啟動線程

在上面的線程,在相應的進程啟動過程中就會被啟動.可以理解為,對象通過調用register(object)觸發finalizer類的初始化.然后,在靜態初始化塊當中,就會啟動相應的回收線程.相應的初始化代碼如下所示:

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是靜態初始化塊,即只要類Finalizer被使用,即會觸發相應的調用.這里使用的線程組是系統線程組,優先級也還算高,被配置為后臺線程.

在使用jstack打印線程時,出現的如圖下所示的線程,即是由這里來啟動的.如下圖所示

 

總結

整個Finalizer即是通過finalReference,由JVM和相應的java類相互配合來協同工作.并不是全部由jvm實現,因此可以認為其也并不是太底層的東西,而是為了實現相應的語義.一切都是正常的java來完成,由jvm配合.了解到整個過程,也是對java本身的運行機制有所了解.

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 青冈县| 库伦旗| 岐山县| 宣化县| 高尔夫| 自贡市| 兴业县| 济宁市| 安图县| 仙居县| 永泰县| 台南市| 滦南县| 安顺市| 修武县| 东丰县| 庆元县| 洛浦县| 拜泉县| 宁强县| 内乡县| 壤塘县| 商城县| 施秉县| 东乌珠穆沁旗| 双城市| 当涂县| 兴仁县| 巧家县| 兴国县| 平罗县| 枣阳市| 隆昌县| 卓尼县| 丹寨县| 虹口区| 宽甸| 清河县| 石柱| 金寨县| 卢氏县|