深入理解Java弱引用

Java中的引用類型

Java中存在四種引用盹沈,它們由強到弱依次是:強引用、軟引用吃谣、弱引用乞封、虛引用。下面我們簡單介紹下除弱引用外的其他三種引用:

  • 強引用(Strong Reference):通常我們通過new來創(chuàng)建一個新對象時返回的引用就是一個強引用岗憋,若一個對象通過一系列強引用可到達肃晚,它就是強可達的(strongly reachable),那么它就不被回收
  • 弱引用(Weak Reference):弱引用的對象擁有更短暫的生命周期仔戈。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中关串,一旦發(fā)現(xiàn)了只具有弱引用的對象拧廊,不管當前內(nèi)存空間足夠與否,都會回收它的內(nèi)存
  • 軟引用(Soft Reference):軟引用和弱引用的區(qū)別在于晋修,若一個對象是弱引用可達吧碾,無論當前內(nèi)存是否充足它都會被回收,而軟引用可達的對象在內(nèi)存不充足時才會被回收飞蚓,因此軟引用要比弱引用“強”一些
  • 虛引用(Phantom Reference):虛引用是Java中最弱的引用滤港,那么它弱到什么程度呢?它是如此脆弱以至于我們通過虛引用甚至無法獲取到被引用的對象趴拧,虛引用存在的唯一作用就是當它指向的對象被回收后溅漾,虛引用本身會被加入到引用隊列中,用作記錄它指向的對象已被回收著榴。

判斷弱引用對象的關鍵在于只具有弱引用的對象添履,也就是說,如果一個對象有強引用脑又,那么在系統(tǒng)GC時双炕,是不會回收此對象的,也不會釋放弱引用裙犹。

為什么使用弱引用

Java常通過使用弱引用來避免內(nèi)存泄漏阵谚,例如在JDK中有一種內(nèi)存變量ThreadLocal,通過ThreadLocal變量可以使共享的變量在不同的線程中有不同的副本严卖,原理是在每一個Thread有一個threadLocalMap的屬性席舍,用來存放ThreadLocal對象,ThreadLocalMap中是通過一個Entry[]的散列表存放ThreadLocal變量以及ThreadLocal的value哮笆,而作為Entry的key的ThreadLocal就是使用的弱引用来颤,結(jié)構如下:

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

Entry通過繼承了WeakReference并通過get、set設置ThreadLocal為Entry的referent稠肘。

這里為什么要使用弱引用呢福铅?

原因是如果不使用弱引用,那么當持有value的強引用釋放掉后项阴,當線程沒有回收釋放時滑黔,threadLocalMap會一直持有ThreadLocal以及value的強應用,導致value不能夠被回收环揽,從而造成內(nèi)存泄漏拷沸。

通過使用弱引用,當ThreadLocal的強引用釋放掉后薯演,通過一次系統(tǒng)gc檢查撞芍,發(fā)現(xiàn)ThreadLocal對象只有threadLocalMap中Entry的若引用持有,此時根據(jù)弱引用的機制就會回收ThreadLocal對象跨扮,從而避免了內(nèi)存泄露序无。當然ThreadLocal還有一些額外的保護措施验毡,詳細分析可以參考:死磕Java源碼之ThreadLocal實現(xiàn)分析

這里我們可以通過一個示例來驗證一下:

WeakReferenceDemo.java

import java.lang.ref.WeakReference;

/**
 * 弱引用回收測試
 */
public class WeakReferenceDemo {

    public static WeakReference<String> weakReference1;
    public static WeakReference<String> weakReference2;

    public static void main(String[] args) {

        test1();
        //可以輸出hello值,此時兩個弱引用扔持有對象帝嗡,而且未進行gc
        System.out.println("未進行gc時晶通,只有弱引用指向value內(nèi)存區(qū)域:" + weakReference1.get());

        //此時已無強一用執(zhí)行"value"所在內(nèi)存區(qū)域,gc時會回收弱引用
        System.gc();

        //此時輸出都為nuill
        System.out.println("進行gc時哟玷,只有弱引用指向value內(nèi)存區(qū)域:" + weakReference1.get());

    }

    public static void test1() {
        String hello = new String("value");

        weakReference1 = new WeakReference<>(hello);

        System.gc();
        //此時gc不會回收弱引用狮辽,因為字符串"value"仍然被hello對象強引用
        System.out.println("進行gc時,強引用與弱引用同時指向value內(nèi)存區(qū)域:" + weakReference1.get());

    }
}

輸出:

進行gc時巢寡,強引用與弱引用同時指向value內(nèi)存區(qū)域:value
未進行gc時喉脖,只有弱引用指向value內(nèi)存區(qū)域:value
進行gc時,只有弱引用指向value內(nèi)存區(qū)域:null

分析輸出結(jié)果可以看出:

當有強引用指向value內(nèi)存區(qū)域時抑月,即使進行gc树叽,弱引用也不會被釋放,對象不回被回收谦絮。

當無強引用指向value內(nèi)存區(qū)域是题诵,此時進行gc,弱引用會被釋放层皱,對象將會執(zhí)行回收流程性锭。

引用隊列

下面我們來簡單地介紹下引用隊列的概念。實際上叫胖,WeakReference類有兩個構造函數(shù):

//創(chuàng)建一個指向給定對象的弱引用``WeakReference(T referent) 
//創(chuàng)建一個指向給定對象并且登記到給定引用隊列的弱引用``WeakReference(T referent, ReferenceQueue<? ``super` `T> q)

我們可以看到第二個構造方法中提供了一個ReferenceQueue類型的參數(shù)草冈,通過提供這個參數(shù),我們便把創(chuàng)建的弱引用對象注冊到了一個引用隊列上臭家,這樣當它被垃圾回收器清除時疲陕,就會把它送入這個引用隊列中方淤,我們便可以對這些被清除的弱引用對象進行統(tǒng)一管理钉赁。

參考:
http://www.reibang.com/p/640f2c0ac4b0
https://www.cnblogs.com/fengbs/p/7019687.html
http://www.importnew.com/21206.html

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市携茂,隨后出現(xiàn)的幾起案子你踩,更是在濱河造成了極大的恐慌,老刑警劉巖讳苦,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件带膜,死亡現(xiàn)場離奇詭異,居然都是意外死亡鸳谜,警方通過查閱死者的電腦和手機膝藕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咐扭,“玉大人芭挽,你說我怎么就攤上這事滑废。” “怎么了袜爪?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵蠕趁,是天一觀的道長。 經(jīng)常有香客問我辛馆,道長俺陋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任昙篙,我火速辦了婚禮腊状,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瓢对。我一直安慰自己寿酌,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布硕蛹。 她就那樣靜靜地躺著醇疼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪法焰。 梳的紋絲不亂的頭發(fā)上秧荆,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音埃仪,去河邊找鬼乙濒。 笑死,一個胖子當著我的面吹牛卵蛉,可吹牛的內(nèi)容都是我干的颁股。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼傻丝,長吁一口氣:“原來是場噩夢啊……” “哼甘有!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起葡缰,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤亏掀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后泛释,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滤愕,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年怜校,在試婚紗的時候發(fā)現(xiàn)自己被綠了间影。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡茄茁,死狀恐怖魂贬,靈堂內(nèi)的尸體忽然破棺而出蔓搞,到底是詐尸還是另有隱情,我是刑警寧澤随橘,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布喂分,位于F島的核電站,受9級特大地震影響机蔗,放射性物質(zhì)發(fā)生泄漏蒲祈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一萝嘁、第九天 我趴在偏房一處隱蔽的房頂上張望梆掸。 院中可真熱鬧,春花似錦牙言、人聲如沸酸钦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卑硫。三九已至,卻和暖如春蚕断,著一層夾襖步出監(jiān)牢的瞬間欢伏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工亿乳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留硝拧,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓葛假,卻偏偏與公主長得像障陶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子聊训,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容