ThreadLocal 內存泄漏問題深刻分析

寫在前面

ThreadLocal 基本用法本文就不介紹了,若是有不知道的小夥伴能夠先了解一下,本文只研究 ThreadLocal 內存泄漏這一問題。數組

ThreadLocal 會發生內存泄漏嗎?

先給出結論:若是你使用不當是有可能發生內存泄露的spa

<br/>線程

每一個 Thread 裏面都有一個 ThreadLocalMap,而 ThreadLocalMap 中真正承載數據的是一個 Entry 數組,Entry 的 Key 是 threadlocal 對象的弱引用。對象

這裏或許有的小夥伴有疑問,Entry 的 Key 是 threadlocal 對象的弱引用,爲何要用弱引用,換成強引用行不行?blog

首先,咱們先了解一下什麼是弱引用?內存

弱引用通常是用來描述非必需對象的,被弱引用關聯的對象只能生存到下一次垃圾收集發生以前。 當垃圾收集器工做時,不管當前內存是否足夠,都會回收掉只被弱引用關聯的對象

實際開發中,當咱們不須要 threadlocal 後,爲了 GC 將 threadlocal 變量置爲 null,沒有任何強引用指向堆中的 threadlocal 對象時,堆中的 threadlocal 對象將會被 GC 回收,假設如今 Key 持有的是 threadlocal 對象的強引用,若是當前線程仍然在運行,那麼從當前線程一直到 threadlocal 對象仍是存在強引用,因爲當前線程仍在運行的緣由致使 threadlocal 對象沒法被 GC,這就發生了內存泄漏。相反,弱引用就不存在此問題,當棧中的 threadlocal 變量置爲 null 後,堆中的 threadlocal 對象只有一個 Key 的弱引用關聯,下一次 GC 的時候堆中的 threadlocal 對象就會被回收,使用弱引用對於 threadlocal 對象而言是不會發生內存泄漏的開發

那麼,第二個問題來了,是否是 Key 持有的是 threadlocal 對象的弱引用就必定不會發生內存泄漏呢?rem

結論是:若是你使用不當仍是有可能發生內存泄露,可是,這裏發生內存泄漏的地方和上面不一樣。get

當 threadlocal 使用完後,將棧中的 threadlocal 變量置爲 null,threadlocal 對象下一次 GC 會被回收,那麼 Entry 中的與之關聯的弱引用 key 就會變成 null,若是此時當前線程還在運行,那麼 Entry 中的 key 爲 null 的 Value 對象並不會被回收(存在強引用),這就發生了內存泄漏,固然這種內存泄漏分狀況,若是當前線程執行完畢會被回收,那麼 Value 天然也會被回收,可是若是使用的是線程池呢,線程跑完任務之後放回線程池(線程沒有銷燬,不會被回收),Value 會一直存在,這就發生了內存泄漏。it

如何更好的下降內存泄漏的風險呢?

ThreadLocal 爲了下降內存泄露的可能性,在 set,get,remove 的時候都會清除此線程 ThreadLocalMap 裏 Entry 數組中全部 Key 爲 null 的 Value。因此,當前線程使用完 threadlocal 後,咱們能夠經過調用 ThreadLocal 的 remove 方法進行清除從而下降內存泄漏的風險。

最後

若是你們想要實時關注我更新的文章以及我分享的乾貨的話,能夠關注個人公衆號 咱們都是小白鼠

相關文章
相關標籤/搜索