深入分析 ThreadLocal 內(nèi)存泄漏問題

前言

ThreadLocal 的作用是提供線程內(nèi)的局部變量纽哥,這種變量在線程的生命周期內(nèi)起作用弓摘,減少同一個線程內(nèi)多個函數(shù)或者組件之間一些公共變量的傳遞的復(fù)雜度。但是如果濫用 ThreadLocal,就可能會導(dǎo)致內(nèi)存泄漏硼瓣。下面,我們將圍繞三個方面來分析 ThreadLocal 內(nèi)存泄漏的問題

  • ThreadLocal 實(shí)現(xiàn)原理
  • ThreadLocal為什么會內(nèi)存泄漏
  • ThreadLocal 最佳實(shí)踐

ThreadLocal 實(shí)現(xiàn)原理


ThreadLocal的實(shí)現(xiàn)是這樣的:每個Thread 維護(hù)一個 ThreadLocalMap 映射表置谦,這個映射表的 keyThreadLocal 實(shí)例本身堂鲤,value 是真正需要存儲的 Object

也就是說 ThreadLocal 本身并不存儲值媒峡,它只是作為一個 key 來讓線程從 ThreadLocalMap 獲取 value筑累。值得注意的是圖中的虛線,表示 ThreadLocalMap 是使用 ThreadLocal 的弱引用作為 Key 的丝蹭,弱引用的對象在 GC 時會被回收慢宗。

ThreadLocal為什么會內(nèi)存泄漏

ThreadLocalMap使用ThreadLocal的弱引用作為key,如果一個ThreadLocal沒有外部強(qiáng)引用來引用它奔穿,那么系統(tǒng) GC 的時候镜沽,這個ThreadLocal勢必會被回收,這樣一來贱田,ThreadLocalMap中就會出現(xiàn)keynullEntry缅茉,就沒有辦法訪問這些keynullEntryvalue,如果當(dāng)前線程再遲遲不結(jié)束的話男摧,這些keynullEntryvalue就會一直存在一條強(qiáng)引用鏈:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永遠(yuǎn)無法回收蔬墩,造成內(nèi)存泄漏译打。

其實(shí),ThreadLocalMap的設(shè)計(jì)中已經(jīng)考慮到這種情況拇颅,也加上了一些防護(hù)措施:在ThreadLocalget(),set(),remove()的時候都會清除線程ThreadLocalMap里所有keynullvalue奏司。

但是這些被動的預(yù)防措施并不能保證不會內(nèi)存泄漏:

  • 使用staticThreadLocal,延長了ThreadLocal的生命周期樟插,可能導(dǎo)致的內(nèi)存泄漏(參考ThreadLocal 內(nèi)存泄露的實(shí)例分析)韵洋。
  • 分配使用了ThreadLocal又不再調(diào)用get(),set(),remove()方法,那么就會導(dǎo)致內(nèi)存泄漏黄锤。

為什么使用弱引用

從表面上看內(nèi)存泄漏的根源在于使用了弱引用搪缨。網(wǎng)上的文章大多著重分析ThreadLocal使用了弱引用會導(dǎo)致內(nèi)存泄漏,但是另一個問題也同樣值得思考:為什么使用弱引用而不是強(qiáng)引用鸵熟?

我們先來看看官方文檔的說法:

To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys.
為了應(yīng)對非常大和長時間的用途副编,哈希表使用弱引用的 key。

下面我們分兩種情況討論:

  • key 使用強(qiáng)引用:引用的ThreadLocal的對象被回收了流强,但是ThreadLocalMap還持有ThreadLocal的強(qiáng)引用痹届,如果沒有手動刪除,ThreadLocal不會被回收煮盼,導(dǎo)致Entry內(nèi)存泄漏短纵。
  • key 使用弱引用:引用的ThreadLocal的對象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用僵控,即使沒有手動刪除香到,ThreadLocal也會被回收。value在下一次ThreadLocalMap調(diào)用set,get报破,remove的時候會被清除悠就。

比較兩種情況,我們可以發(fā)現(xiàn):由于ThreadLocalMap的生命周期跟Thread一樣長充易,如果都沒有手動刪除對應(yīng)key梗脾,都會導(dǎo)致內(nèi)存泄漏,但是使用弱引用可以多一層保障:弱引用ThreadLocal不會內(nèi)存泄漏盹靴,對應(yīng)的value在下一次ThreadLocalMap調(diào)用set,get,remove的時候會被清除炸茧。

因此,ThreadLocal內(nèi)存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一樣長稿静,如果沒有手動刪除對應(yīng)key就會導(dǎo)致內(nèi)存泄漏梭冠,而不是因?yàn)槿跻谩?/p>

ThreadLocal 最佳實(shí)踐

綜合上面的分析,我們可以理解ThreadLocal內(nèi)存泄漏的前因后果改备,那么怎么避免內(nèi)存泄漏呢控漠?

  • 每次使用完ThreadLocal,都調(diào)用它的remove()方法,清除數(shù)據(jù)盐捷。

在使用線程池的情況下偶翅,沒有及時清理ThreadLocal,不僅是內(nèi)存泄漏的問題碉渡,更嚴(yán)重的是可能導(dǎo)致業(yè)務(wù)邏輯出現(xiàn)問題聚谁。所以,使用ThreadLocal就跟加鎖完要解鎖一樣爆价,用完就清理垦巴。

參考文章
Java并發(fā)包學(xué)習(xí)七 解密ThreadLocal
ThreadLocal可能引起的內(nèi)存泄露

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末媳搪,一起剝皮案震驚了整個濱河市铭段,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秦爆,老刑警劉巖序愚,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異等限,居然都是意外死亡爸吮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門望门,熙熙樓的掌柜王于貴愁眉苦臉地迎上來形娇,“玉大人,你說我怎么就攤上這事筹误⊥┰纾” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵厨剪,是天一觀的道長哄酝。 經(jīng)常有香客問我,道長祷膳,這世上最難降的妖魔是什么陶衅? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮直晨,結(jié)果婚禮上搀军,老公的妹妹穿的比我還像新娘。我一直安慰自己勇皇,他們只是感情好罩句,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著儒士,像睡著了一般的止。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上着撩,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天诅福,我揣著相機(jī)與錄音匾委,去河邊找鬼。 笑死氓润,一個胖子當(dāng)著我的面吹牛赂乐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咖气,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼挨措,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了崩溪?” 一聲冷哼從身側(cè)響起浅役,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伶唯,沒想到半個月后觉既,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乳幸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年瞪讼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粹断。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡符欠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瓶埋,到底是詐尸還是另有隱情希柿,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布悬赏,位于F島的核電站狡汉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闽颇。R本人自食惡果不足惜盾戴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兵多。 院中可真熱鬧尖啡,春花似錦、人聲如沸剩膘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怠褐。三九已至畏梆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奠涌。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工宪巨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溜畅。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓捏卓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親慈格。 傳聞我的和親對象是個殘疾皇子怠晴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

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