JAVA引用(WeakHashMap、Cleaner)

Expunge 刪除哥纫,抹去
stale   陳腐霉旗、老舊的

Reference 引用類

強引用、軟引用蛀骇、弱引用厌秒、虛引用

軟引用、弱引用擅憔、虛引用鸵闪,可以配合ReferenceQueue實現對象被回收時候的監(jiān)聽

Reference

重要屬性:

1. private T referent;       
weakHashMap中就是那個Entry的Key   Treated specially by GC

2. volatile ReferenceQueue<? super T> queue;
Reference隊列,GC后Reference對象會被加到這里面暑诸,是放到隊列頭部蚌讼。

3. private static Lock lock = new Lock();
GC時候必須要獲得這個鎖

4. private static Reference<Object> pending = null;
跟虛擬機,GC打交道的个榕。 GC后Reference對象會被GC自動設置到這個引用中篡石,然后由ReferenceHandler線程把他放到ReferenceQueue里面.
    
5. transient private Reference<T> discovered; 
跟虛擬機,GC打交道的  used by VM 

6. volatile Reference next;
ReferenceQueue是linkedList類似是實現西采,鏈表結構凰萨,Reference就相當于其中的Node,有一個next的指針指向下一個對象沟蔑。

ReferenceHandler 內部類:

  1. 在Reference類的靜態(tài)代碼塊中初始化,然后運行狱杰。
  2. 主要功能是在tryHandlePending()方法中瘦材,把Reference類的靜態(tài)變量pending指向的Reference對象丟到他自己的queue中。
  3. 于此同時仿畸,如果pending所指的Reference對象是Cleaner食棕,那么還會執(zhí)行Cleaner的clean方法朗和,而且不會放到queue中,執(zhí)行了clean方法后就返回了簿晓。

Cleaner在DirectByteBuffer中有使用眶拉,下面介紹.

Cleaner類

public class Cleaner extends PhantomReference<Object> 集成虛引用, 也就是說cleaner的var0只要他強引用消失了,那么var0所指的對象就隨時會被GC掉憔儿。

//創(chuàng)建方法忆植,add方法也是把cleaner自身構建成一個鏈表結構
public static Cleaner create(Object var0, Runnable var1) {
   return var1 == null ? null : add(new Cleaner(var0, var1));
}
private Cleaner(Object var1, Runnable var2) {
   super(var1, dummyQueue);
   this.thunk = var2;
}

clean方法,在Reference的tryHandlePending方法中會執(zhí)行谒臼,即Cleaner關聯的對象被GC放到pending中朝刊,然后ReferenceHandler線程執(zhí)行tryHandlePending時候執(zhí)行。

    public void clean() {
        //刪除自身節(jié)點
        if (remove(this)) {
            try {
            //執(zhí)行創(chuàng)建時候傳進來的runnable對象的run方法蜈缤,執(zhí)行相關的業(yè)務邏輯
            //比如DirectByteBuffer類中拾氓,他有個cleaner,run方法是用于釋放直接內存
            //詳見下
                this.thunk.run();
            } catch (final Throwable var2) {
                //省略底哥。咙鞍。。
            }
        }
    }

Cleaner在DirectByteBuffer中有使用趾徽,下面介紹.

DirectByteBuffer中Cleaner的使用

DirectByteBuffer基于unsafe類的allocateMemory來分配直接內存使用续滋。

基于Cleaner來進行直接內存的釋放。

直接內存申請附较,釋放流程:
  1. new DirectByteBuffer(1024)構建對象吃粒,構造方法內部調用Unsafe.allocateMemory申請到直接內存(不歸JVM GC管轄)
  2. 構造方法內部還調用``Cleaner.create(this, new Deallocator(base, size, cap))`把當前DirectByteBuffer設置為虛引用潦俺,并設置一個Deallocator的runnable類拒课。
  3. 當DirectByteBuffer強引用消失,即不可達之后事示,由于Cleaner是虛引用早像,不影響GC,所以DirectByteBuffer被GC掉了
  4. 與此同時肖爵,Cleaner對象也被GC設置到Reference的靜態(tài)屬性pending中(這個時候Cleaner即Reference的Referent引用指向的DirectByteBuffer已經是null了)
  5. Reference中的ReferenceHandler線程執(zhí)行tryHandlePending卢鹦,處理pending,即該Cleaner
  6. tryHandlePending中調用Cleaner的clean方法劝堪,clean方法內部調用構建時候傳入的runnable對象的run方法冀自,即Deallocator的run方法。
  7. Deallocator的run方法中調用了unsafe.freeMemory(address);來釋放DirectByteBuffer在構建時候申請的直接內存
  8. 以此來完成直接內存的釋放

WeakHashMap

https://hongjiang.info/java-referencequeue/

以前設計緩存時也曾過用WeakHashMap來實現秒啦,對Java的Reference稍做過一些了解熬粗,其實這個問題,歸根到底余境,是個Java GC的問題驻呐,由垃圾回收器與ReferenceQueue的交互方式決定的灌诅。WeakHashMap的實現也是通過ReferenceQueue這個“監(jiān)聽器”來優(yōu)雅的實現自動刪除那些引用不可達的key的。

Entry類繼承了WeakReference, 其中的Key是弱引用含末,并且WeakHashMap中定義了一個ReferenceQueue猜拾,用于監(jiān)聽key的回收

  //Entry類繼承弱引用
  private static class Entry<K,V> extends WeakReference<Object> {}
  
  //WeakHashMap中的實例變量用于監(jiān)聽key的回收
  private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
流程
  1. 當WeakHashMap中Key沒有其他強引用時候,發(fā)生了一次任意GC佣盒,由于Entry的Key是弱引用挎袜,那么被GC回收。

  2. 被GC回收的同時肥惭,Entry類(繼承了弱引用)會由GC自動放入到Reference的靜態(tài)屬性pending中宋雏。

  3. Reference類在類初始化后有個static代碼塊,里面啟動了一個高優(yōu)先級的daemon線程务豺,用于把pending指向的Reference對象放到ReferenceQueue中

  4. 經過3后磨总,Entry就被丟到了ReferenceQueue中

  5. 當你在GC后調用WeakHashMap的get、put笼沥、size等方法時候蚪燕,他會調用自己的expungeStaleEntries()方法。

  6. expungeStaleEntries方法會poll出queue中的Entry類奔浅,然后把entry類處理下馆纳,value=null,釋放掉value的強引用汹桦,然后處理前后的指針鲁驶,size--之類。

  7. 經過6之后舞骆,key對應的value強引用也被抹去了钥弯,所以GC也可以把value以及整個entry回收掉。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末督禽,一起剝皮案震驚了整個濱河市脆霎,隨后出現的幾起案子,更是在濱河造成了極大的恐慌狈惫,老刑警劉巖睛蛛,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異胧谈,居然都是意外死亡忆肾,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門菱肖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來客冈,“玉大人,你說我怎么就攤上這事蔑滓〗季疲” “怎么了遇绞?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長燎窘。 經常有香客問我摹闽,道長,這世上最難降的妖魔是什么褐健? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任付鹿,我火速辦了婚禮,結果婚禮上蚜迅,老公的妹妹穿的比我還像新娘舵匾。我一直安慰自己,他們只是感情好谁不,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布坐梯。 她就那樣靜靜地躺著,像睡著了一般刹帕。 火紅的嫁衣襯著肌膚如雪吵血。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天偷溺,我揣著相機與錄音蹋辅,去河邊找鬼。 笑死挫掏,一個胖子當著我的面吹牛侦另,可吹牛的內容都是我干的。 我是一名探鬼主播尉共,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼褒傅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了爸邢?” 一聲冷哼從身側響起樊卓,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎杠河,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體浇辜,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡券敌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了柳洋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片待诅。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖熊镣,靈堂內的尸體忽然破棺而出卑雁,到底是詐尸還是另有隱情募书,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布测蹲,位于F島的核電站莹捡,受9級特大地震影響,放射性物質發(fā)生泄漏扣甲。R本人自食惡果不足惜篮赢,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琉挖。 院中可真熱鬧启泣,春花似錦、人聲如沸示辈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矾麻。三九已至坠敷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間射富,已是汗流浹背膝迎。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胰耗,地道東北人限次。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像柴灯,于是被迫代替她去往敵國和親卖漫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355