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

溫馨提示×

溫馨提示×

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

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

threadLocal出現內存泄漏的原因是什么

發布時間:2021-06-22 16:57:27 來源:億速云 閱讀:739 作者:Leah 欄目:編程語言

這篇文章給大家介紹threadLocal出現內存泄漏的原因是什么,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

內存泄漏的現象 執行 cn.enjoyedu.ch2.threadlocal 下的 ThreadLocalOOM,并將堆內存大小設 置為-Xmx256m, 我們啟用一個線程池,大小固定為 5 個線程

threadLocal出現內存泄漏的原因是什么

場景 1:首先任務中不執行任何有意義的代碼,當所有的任務提交執行完成 后,可以看見,我們這個應用的內存占用基本上為 25M 左右

threadLocal出現內存泄漏的原因是什么

場景 2:然后我們只簡單的在每個任務中 new 出一個數組,執行完成后我們 可以看見,內存占用基本和場景 1 同

threadLocal出現內存泄漏的原因是什么

場景 3:當我們啟用了 ThreadLocal 以后:,執行完成后我們可以看見,內存占用變為了 100M 左右

threadLocal出現內存泄漏的原因是什么

場景 4:于是,我們加入一行代碼,再執行,看看內存情況:

threadLocal出現內存泄漏的原因是什么

可以看見,內存占用基本和場景 1 同。 這就充分說明,場景 3,當我們啟用了 ThreadLocal 以后確實發生了內存泄 漏。

分析 :

        根據我們前面對 ThreadLocal 的分析,我們可以知道每個 Thread 維護一個 ThreadLocalMap,這個映射表的 key 是 ThreadLocal 實例本身,value 是真正需 要存儲的 Object,也就是說 ThreadLocal 本身并不存儲值,它只是作為一個 key 來讓線程從 ThreadLocalMap 獲取 value。仔細觀察 ThreadLocalMap,這個 map 是使用 ThreadLocal 的弱引用作為 Key 的,弱引用的對象在 GC 時會被回收。因此使用了 ThreadLocal 后,引用鏈如下圖:

threadLocal出現內存泄漏的原因是什么

圖中的虛線表示弱引用

        這樣,當把 threadlocal 變量置為 null 以后,沒有任何強引用指向 threadlocal 實例,所以 threadlocal 將會被 gc 回收。導致ThreadLocalMap 中就會出現 key 為 null 的 Entry,就沒有辦法訪問這些 key 為 null 的 Entry 的 value,如果當前 線程再遲遲不結束的話,這些 key 為 null 的 Entry 的 value 就會一直存在一條強 引用鏈:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,而這塊 value 永 遠不會被訪問到了,所以存在著內存泄露。

        只有當前 thread 結束以后,current thread 就不會存在棧中,強引用斷開, Current Thread、Map value 將全部被 GC 回收。最好的做法是不在需要使用 ThreadLocal 變量后,都調用它的 remove()方法,清除數據。

        所以回到我們前面的實驗場景,場景 3 中,雖然線程池里面的任務執行完畢 了,但是線程池里面的 5 個線程會一直存在直到 JVM 退出,我們 set 了線程的 localVariable 變量后沒有調用 localVariable.remove()方法,導致線程池里面的 5 個 線程的 threadLocals 變量里面的 new LocalVariable()實例沒有被釋放。

        其實考察 ThreadLocal 的實現,我們可以看見,無論是 get()、set()在某些時 候,調用了 expungeStaleEntry 方法用來清除 Entry 中 Key 為 null 的 Value,但是 這是不及時的,也不是每次都會執行的,所以一些情況下還是會發生內存泄露。 只有 remove()方法中顯式調用了 expungeStaleEntry 方法。

        從表面上看內存泄漏的根源在于使用了弱引用,但是另一個問題也同樣值得 思考:為什么使用弱引用而不是強引用?

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

            key 使用強引用:對 ThreadLocal 對象實例的引用被置為 null 了,但是 ThreadLocalMap 還持有這個 ThreadLocal 對象實例的強引用,如果沒有手動刪除, ThreadLocal 的對象實例不會被回收,導致 Entry 內存泄漏。

        key 使用弱引用:對 ThreadLocal 對象實例的引用被被置為 null 了,由于 ThreadLocalMap 持有 ThreadLocal 的弱引用,即使沒有手動刪除,ThreadLocal 的 對象實例也會被回收。value 在下一次 ThreadLocalMap 調用 set,get,remove 都 有機會被回收。

        比較兩種情況

                我們可以發現:由于 ThreadLocalMap 的生命周期跟 Thread 一樣長,如果都沒有手動刪除對應 key,都會導致內存泄漏,但是使用弱引用可 以多一層保障。

                因此,ThreadLocal 內存泄漏的根源是:由于 ThreadLocalMap 的生命周期跟 Thread 一樣長,如果沒有手動刪除對應 key 就會導致內存泄漏,而不是因為弱引 用。

        總結:

                JVM 利用設置 ThreadLocalMap 的 Key 為弱引用,來避免內存泄露。

                JVM 利用調用 remove、get、set 方法的時候,回收弱引用。

                當 ThreadLocal 存儲很多 Key 為 null 的 Entry 的時候,而不再去調用 remove、 get、set 方法,那么將導致內存泄漏。

                使用線程池+ ThreadLocal 時要小心,因為這種情況下,線程是一直在不斷的 重復運行的,從而也就造成了 value 可能造成累積的情況。

關于threadLocal出現內存泄漏的原因是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

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

AI

化州市| 资溪县| 墨江| 个旧市| 齐齐哈尔市| 陆丰市| 福鼎市| 教育| 青冈县| 内江市| 肃宁县| 韶关市| 定南县| 江津市| 青冈县| 资源县| 德令哈市| 讷河市| 乐昌市| 东兴市| 武乡县| 穆棱市| 磐安县| 沙洋县| 饶平县| 南澳县| 越西县| 江油市| 区。| 连平县| 阜宁县| 赤峰市| 朝阳区| 新乐市| 云南省| 雷波县| 德庆县| 万载县| 喀喇| 柘荣县| 建始县|