深入分析 ThreadLocal 內存泄漏問題

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

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

  • ThreadLocal 實現原理
  • ThreadLocal為什么會內存泄漏
  • ThreadLocal 最佳實踐

ThreadLocal 實現原理

ThreadLocal
ThreadLocal的實現是這樣的:每個Thread 維護一個 ThreadLocalMap 映射表,這個映射表的 keyThreadLocal 實例本身,value 是真正需要存儲的 Object

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

ThreadLocal為什么會內存泄漏

ThreadLocalMap使用ThreadLocal的弱引用作為key,如果一個ThreadLocal沒有外部強引用來引用它,那么系統 GC 的時候,這個ThreadLocal勢必會被回收,這樣一來,ThreadLocalMap中就會出現keynullEntry,就沒有辦法訪問這些keynullEntryvalue,如果當前線程再遲遲不結束的話,這些keynullEntryvalue就會一直存在一條強引用鏈:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永遠無法回收,造成內存泄漏。

其實,ThreadLocalMap的設計中已經考慮到這種情況,也加上了一些防護措施:在ThreadLocalget(),set(),remove()的時候都會清除線程ThreadLocalMap里所有keynullvalue

但是這些被動的預防措施并不能保證不會內存泄漏:

  • 使用staticThreadLocal,延長了ThreadLocal的生命周期,可能導致的內存泄漏(參考ThreadLocal 內存泄露的實例分析)。
  • 分配使用了ThreadLocal又不再調用get(),set(),remove()方法,那么就會導致內存泄漏。

為什么使用弱引用

從表面上看內存泄漏的根源在于使用了弱引用。網上的文章大多著重分析ThreadLocal使用了弱引用會導致內存泄漏,但是另一個問題也同樣值得思考:為什么使用弱引用而不是強引用?

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

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

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

  • key 使用強引用:引用的ThreadLocal的對象被回收了,但是ThreadLocalMap還持有ThreadLocal的強引用,如果沒有手動刪除,ThreadLocal不會被回收,導致Entry內存泄漏。
  • key 使用弱引用:引用的ThreadLocal的對象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使沒有手動刪除,ThreadLocal也會被回收。value在下一次ThreadLocalMap調用set,getremove的時候會被清除。

比較兩種情況,我們可以發現:由于ThreadLocalMap的生命周期跟Thread一樣長,如果都沒有手動刪除對應key,都會導致內存泄漏,但是使用弱引用可以多一層保障:弱引用ThreadLocal不會內存泄漏,對應的value在下一次ThreadLocalMap調用set,get,remove的時候會被清除

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

ThreadLocal 最佳實踐

綜合上面的分析,我們可以理解ThreadLocal內存泄漏的前因后果,那么怎么避免內存泄漏呢?

  • 每次使用完ThreadLocal,都調用它的remove()方法,清除數據。

在使用線程池的情況下,沒有及時清理ThreadLocal,不僅是內存泄漏的問題,更嚴重的是可能導致業務邏輯出現問題。所以,使用ThreadLocal就跟加鎖完要解鎖一樣,用完就清理。

轉載于:https://my.oschina.net/u/3664884/blog/1790985

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/278181.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/278181.shtml
英文地址,請注明出處:http://en.pswp.cn/news/278181.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何將iPhone應用程序從應用程序庫移動到主屏幕

Justin Duino賈斯汀杜伊諾(Justin Duino)So as to not clutter up your home screen, newly-downloaded apps from the App Store can be sent directly to the App Library. But what if you later want to open the app without digging through the library? Here’s how t…

luogu4389 付公主的背包

題目鏈接:洛谷 題目大意:現在有$n$個物品,每種物品體積為$v_i$,對任意$s\in [1,m]$,求背包恰好裝$s$體積的方案數(完全背包問題)。 數據范圍:$n,m\leq 10^5$ 這道題,看到…

Git與Github的連接與使用

2019獨角獸企業重金招聘Python工程師標準>>> Git與Github的連接與使用 下面繼續,使用git 將項目上傳到GitHub上 首先要有GitHub賬號,這就不用說了,沒有的先注冊,地址:https://github.com 沒有倉庫的話,先新…

ttl電路制作pong游戲_如何玩Mozilla Firefox的隱藏的獨角獸Pong游戲

ttl電路制作pong游戲It seems like every browser has a hidden game these days. Chrome has a dinosaur game, Edge has surfing, and Firefox has . . . unicorn pong? Yep, you read that right—here’s how to play it. 這些天似乎每個瀏覽器都有一個隱藏的游戲。 Chrom…

nginx 注釋配置及詳解

前言 DMZ(Demilitarized Zone) 非軍事區,生產環境 WEB 服務部署的區域,公司的架構為一臺nginx 充當 load balance 服務,負載到兩臺 nginx 上面,反向代理至后臺服務,但是nginx 用的全是默認配置加上 proxy_pass 和 upst…

為什么無法運行谷歌play_什么是Google Play積分,以及如何使用它們?

為什么無法運行谷歌playThe Google Play Store is home to thousands of apps, games, movies, e-books, and more. You might find yourself making a lot of purchases there, so why not get rewarded for it? That’s where Google Play Points come in. Google Play商店提…

2019年春季學期第三周作業

本周作業 本周請大家完成上周挑戰作業的第一部分:給定一個整數數組(包含正負數),找到一個具有最大和的子數組,返回其最大的子數組的和。 例如:[1, -2, 3, 10, -4, 7, 2, -5]的最大子數組為[3, 10, -4, 7, 2] 1).實驗代…

Linux實驗二:linux 常用命令練習

ls命令 列出目錄內容 echo命令 顯示字符串 date命令 顯示或設置系統的日期與時間 cal命令 顯示日歷 who命令 列出登錄用戶信息 chown命令 chgrp命令 改變文件所屬的用戶組 chmod命令 改變文件訪問權限 find命令 在目錄中搜索文件 轉載于:https://www.cnblogs.com/nullno/p/87…

python數據類型之元組類型

#為何要有元組&#xff0c;存放多個值&#xff0c;元組不可變&#xff0c;更多的是用來做查詢 t(1,[1&#xff0c;2,3],a,(1,2)) #ttuple((1,[1,2,3],a,(1,2))) # print(type(t)) <class tuple># #元組可以作為字典的key # d{(1,2):egon} # print(d,type(d),d[(1,2)])# …

短語密碼_使用密碼短語以提高安全性

短語密碼Did you know that Windows supports using passwords of up to 127 characters? I don’t use passwords anymore, and I haven’t for years. I’ve switched to using password phrases instead. 您知道Windows支持使用最多127個字符的密碼嗎&#xff1f; 我不再使…

「單點登錄與權限管理」系列概述

首先&#xff0c;感謝幾位朋友在朋友圈轉發我的文章&#xff0c;小聲的告訴你們&#xff0c;是我主動讓他們幫忙轉發的&#xff1a;&#xff09;在朋友們的分享下&#xff0c;凌晨推送的一篇文章&#xff0c;閱讀人數達到了280多&#xff0c;很滿足&#xff0c;我會堅持寫下去&…

Jupyter notebook: TypeError: __init__() got an unexpected keyword argument 'io_loop 問題

使用環境&#xff1a;Anaconda3&#xff08;Python3.6&#xff09; 創建一個新的notebook時&#xff0c;無法連接到kernel&#xff0c;terminal上顯示錯誤為&#xff1a;TypeError: __init__() got an unexpected keyword argument io_loop 解決方法&#xff1a; conda install…

在Ubuntu Linux中獲取上次訪問的文件時間

Ubuntu Linux has a rich set of commands for manipulating and accessing files. The stat utility gives detailed access to file information, including last accessed and last modified file time. Ubuntu Linux具有一組豐富的用于操作和訪問文件的命令。 stat實用程序…

MySQL新增從庫

項目背景描述&#xff1a;在項目的開始只有一個MySQL實例在運行&#xff0c;后期因為安全性&#xff0c;壓力&#xff0c;備份等原因需要在此實例的基礎上面新增一個從庫。分析&#xff1a;MySQL主從是基于binlog日志來實現的&#xff0c;那么需要主服務器開啟binlog&#xff0…

第一個議題

① 在每個問題后面&#xff0c;請說明哪一章節的什么內容引起了你的提問&#xff0c;提供一些上下文 ② 列出一些事例或資料&#xff0c;支持你的提問 。 ③ 說說你提問題的原因&#xff0c;你說因為自己的假設和書中的不同而提問&#xff0c;還是不懂書中的術語&#xff0c;還…

在Windows Vista中使用符號鏈接

One of the long-awaited features in Windows Vista was the ability to use symbolic links, the way you can in linux. Sadly, they don’t work quite as well as they could, but it’s a big upgrade from prior versions, and has solved a number of problems for me …

shell學習筆記--自我總結

一、文件 touch file # 創建空白文件 rm -rf 目錄名 # 不提示刪除非空目錄(-r:遞歸刪除 -f強制) dos2unix # windows文本轉linux文本 unix2dos # linux文本轉windows文本 enca filename # 查看編碼 安裝 yu…

201671030107胡文艷實驗三作業互評與改進報告

任務1&#xff1a;要給出所點評作業的鏈接地址&#xff0c;點評內容和閱讀心得 讀了你的這篇博客&#xff0c;一方面給我的印象就是排版整齊&#xff0c;內容充實&#xff0c;態度認真&#xff1b;另外一方面就是通過別人反省自己&#xff0c;看了你的博客&#xff0c;我覺得我…

進程handle獲取線程_獲取進程中的線程列表

進程handle獲取線程The System.Diagnostics namespace contains functions that allow you to manage processes, threads, eventlogs and performance information. System.Diagnostics命名空間包含允許您管理進程&#xff0c;線程&#xff0c;事件日志和性能信息的函數。 The…

2018-3-28Linux系統管理(16)計算機網絡基礎

在這一章當中我們講述計算機網絡基礎。一、計算機網絡網絡通信就像人與人之間的交流一樣&#xff0c;說同一種語言&#xff0c;而后雙方進行無障礙的通信交流&#xff0c;那么兩臺主機通信時&#xff0c;它們彼此交換數據的格式的前提為互相理解才可以&#xff0c;我們此前也有…