中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ThreadLocal 為什么會內存泄漏

發布時間:2021-12-17 15:21:59 來源:億速云 閱讀:100 作者:柒染 欄目:大數據

ThreadLocal 為什么會內存泄漏,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

ThreadLocal 解決了什么問題呢?

它是為了解決對象不能被多線程共享訪問的問題,通過 threadLocal.set() 方法將對象實例保存在每個線程自己所擁有的 threadLocalMap 中,這樣的話每個線程都使用自己的對象實例,彼此不會影響從而達到了隔離的作用,這樣就解決了對象在被共享訪問時帶來的線程安全問題

啥意思呢?打個比方,現在公司所有人都要填寫一個表格,但是只有一支筆,這個時候就只能上個人用完了之后,下個人才可以使用,為了保證"筆"這個資源的可用性,只需要保證在接下來每個人的獲取順序就可以了,這就是 lock 的作用,當這支筆被別人用的時候,我就加 lock ,你來了那就進入隊列排隊等待獲取資源(非公平方式那就另外說了),這支筆用完之后就釋放 lock ,然后按照順序給下個人使用

但是完全可以一個人一支筆對不對,這樣的話,你填寫你的表格,我填寫我的表格,咱倆誰都不耽擱誰。這就是 ThreadLocal 在做的事情,因為每個 Thread 都有一個副本,就不存在資源競爭,所以也就不需要加鎖,這不就是拿空間去換了時間嘛

在開始之前,咱們先把 Thread, ThreadLocal, ThreadLocalMap 的關系捋一捋:

ThreadLocal 為什么會內存泄漏

可以看到,在 Thread 中持有一個 ThreadLocalMap , ThreadLocalMap 又是由 Entry 來組成的,在 Entry 里面有 ThreadLocal 和 value  
 

ThreadLocal 為啥動不動就內存泄漏呢?

在這里先給個解釋,后面咱們再詳細分析:

首先是因為 ThreadLocal 是基于 ThreadLocalMap 實現的,其中 ThreadLocalMap 的 Entry 繼承了 WeakReference ,而 Entry 對象中的 key 使用了 WeakReference 封裝,也就是說, Entry 中的 key 是一個弱引用類型,對于弱引用來說,它只能存活到下次 GC 之前

如果此時一個線程調用了 ThreadLocalMap 的 set 設置變量,當前的 ThreadLocalMap 就會新增一條記錄,但由于發生了一次垃圾回收,這樣就會造成一個結果: key 值被回收掉了,但是 value 值還在內存中,而且如果線程一直存在的話,那么它的 value 值就會一直存在

這樣被垃圾回收掉的 key 就會一直存在一條引用鏈: Thread -> ThreadLocalMap -> Entry -> Value :

ThreadLocal 為什么會內存泄漏

就是因為這條引用鏈的存在,就會導致如果 Thread 還在運行,那么 Entry 不會被回收,進而 value 也不會被回收掉,但是 Entry 里面的 key 值已經被回收掉了

這只是一個線程,如果再來一個線程,又來一個線程…多了之后就會造成內存泄漏

知道是怎么造成內存泄漏之后,接下來要做的事情就好說了,不是因為 value 值沒有被回收掉所以才會導致內存泄露的嘛

那使用完 key 值之后,將 value 值通過 remove 方法 remove 掉,這樣的話內存中就不會有 value 值了,也就防止了內存泄漏嘛

 

ThreadLocal 是基于 ThreadLocalMap 實現的?

OK ,上面的內容講完了,接下來一一來看

首先,你怎么知道 ThreadLocal 是基于 ThreadLocalMap 實現的呢?

從源碼知道的~

在源碼中能夠看到下面這幾行代碼:

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

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

代碼中說的很清楚了,在 ThreadLocal 內部維護著 ThreadLocalMap ,而它的 Entry 則繼承自 WeakReference 的 ThreadLocal<?> ,其中 Entry 的 k 為 ThreadLocal , v 為 Object ,在調用 super(k) 時就將 ThreadLocal 實例包裝成了一個 WeakReference

強弱引用這塊內容阿粉就直接放一個表格吧:

引用類型功能特點
強引用 ( Strong Reference )被強引用關聯的對象永遠不會被垃圾回收器回收掉
軟引用( Soft Reference )軟引用關聯的對象,只有當系統將要發生內存溢出時,才會去回收軟引用引用的對象
弱引用 ( Weak Reference )只被弱引用關聯的對象,只要發生垃圾收集事件,就會被回收
虛引用 ( Phantom Reference )被虛引用關聯的對象的唯一作用是能在這個對象被回收器回收時收到一個系統通知

從表格中應該能夠看出來,弱引用的對象只要發生垃圾收集事件,就會被回收

所以弱引用的存活時間也就是下次 GC 之前了

在這里阿粉就有個問題想問問了:為什么 ThreadLocal 采用弱引用,而不是強引用嘞?

在 ThreadLocalMap 上面有些注釋,我在這里摘錄一部分,或許可以從中窺探一二:

To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys

翻譯一下就是:

為了解決非常大且長期使用的問題,哈希表使用了弱引用的 key

假設,假設, ThreadLocal 使用的是強引用,會怎樣呢?

如果是強引用的話,在表格中也能夠看出來,被強引用關聯的對象,永遠都不會被垃圾回收器回收掉

如果引用的 ThreadLocal 對象被回收了,但是 ThreadLocalMap 還持有對 ThreadLocal 的強引用,如果沒有 remove 的話, 在 GC 時進行可達性分析, ThreadLocal 依然可達,這樣就不會對 ThreadLocal 進行回收,但是我們期望的是引用的 ThreadLocal 對象被回收,這樣不就達不到目的了嘛

使用弱引用的話,雖然會出現內存泄漏的問題,但是在 ThreadLocal 生命周期里面,都有對 key 值為 null 時進行回收的處理操作

所以,使用弱引用的話,可以在 ThreadLocal 生命周期中盡可能保證不出現內存泄漏的問題

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

年辖:市辖区| 奎屯市| 喀什市| 扎兰屯市| 邯郸市| 剑河县| 茌平县| 公主岭市| 威宁| 松溪县| 九寨沟县| 岱山县| 乐业县| 和田市| 陈巴尔虎旗| 揭东县| 桂东县| 禹城市| 马山县| 汉源县| 济南市| 罗源县| 右玉县| 灵寿县| 轮台县| 隆回县| 穆棱市| 迁安市| 洪雅县| 康平县| 凤冈县| 东乌珠穆沁旗| 北票市| 怀化市| 清苑县| 叙永县| 辽阳市| 铜梁县| 林芝县| 郎溪县| 孝昌县|