成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

ThreadLocal 為什么會內(nèi)存泄漏?如何解決?

開發(fā) 前端
ThreadLocal是 Java 提供的一種線程封閉機制,每個線程都可以存儲自己的變量副本,互不干擾。那么問題來了:這些變量存儲在哪里呢? 其實,它們存儲在 Thread 里,每個 Thread 內(nèi)部都有一個 ThreadLocalMap,專門用來存儲 ThreadLocal 變量。

最近,朋友小王在參加某大廠的社招面試,面試官笑瞇瞇地問:“說說ThreadLocal的作用?有啥缺點?”

小王心里一喜,這可是老生常談的問題,于是滔滔不絕地講了一通,啥線程隔離、啥存儲上下文信息、啥用戶Session,統(tǒng)統(tǒng)都擺上了臺面。

面試官聽完點點頭,接著拋出一個靈魂拷問:“那你能分析一下ThreadLocal的內(nèi)存泄漏問題嗎?以及如何避免?”

小王:“呃……這……ThreadLocal還能內(nèi)存泄漏?”

完了!涼涼!

回來后,小王苦哈哈地跟我吐槽,我趕緊給他補了一課。今天,我們就一起來探究:ThreadLocal的內(nèi)存泄漏問題及其解決方案!

ThreadLocal 的底層實現(xiàn)

ThreadLocal是 Java 提供的一種線程封閉機制,每個線程都可以存儲自己的變量副本,互不干擾。那么問題來了:這些變量存儲在哪里呢?

其實,它們存儲在 Thread 里,每個 Thread 內(nèi)部都有一個 ThreadLocalMap,專門用來存儲 ThreadLocal 變量。

我們來看 Thread 類的源碼(JDK 8):

圖片圖片

嗯,這個 threadLocals 變量就是核心,它的類型是 ThreadLocalMap,專門用來存儲 ThreadLocal 的值。

再看看 ThreadLocalMap 的內(nèi)部結(jié)構(gòu)(簡化版):

圖片圖片

我們發(fā)現(xiàn)了一個關(guān)鍵點:Entry 繼承自 WeakReference(弱引用)。這意味著 ThreadLocal 本身是弱引用,但 value 卻是強引用!

那么問題來了!

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

我們來看這樣一段代碼:

圖片圖片

這段代碼有兩個問題:

  • threadLocal 被置為 null,但 value 依然存在!
  • ThreadLocal 是弱引用,GC 可能會回收它,但 value 依然被 ThreadLocalMap 強引用著!

當 GC 發(fā)生時:

  • ThreadLocal 變量本身會被清理掉,因為它是弱引用。
  • ThreadLocalMap 的 Entry.key == null,但 value 還在,占據(jù)大量內(nèi)存!

這樣,如果當前線程是線程池的線程,那么這個 value 就一直不會被回收,導致內(nèi)存泄漏!

這,就是 ThreadLocal 內(nèi)存泄漏 的真正原因!

如何避免 ThreadLocal 內(nèi)存泄漏?

既然知道了原因,那解決方案也就呼之欲出了!

方案 1:手動 remove()

最簡單、最有效的方式,就是在使用完 ThreadLocal 變量后,手動調(diào)用 remove() 方法。

圖片圖片

這樣,ThreadLocalMap 里的 Entry 就會被清理掉,value 也就不會泄漏了!

正確示例:

圖片圖片

為什么要用 finally?

因為如果發(fā)生異常,導致 remove() 沒有執(zhí)行,那么 value 還是會泄漏!所以,我們一定要在 finally 代碼塊里手動清理。

方案 2:使用 Static 變量避免多個 ThreadLocal 實例

有時候,我們不希望 ThreadLocal 被 GC 過早回收,可以使用 static 變量 來持有它,確保 ThreadLocal 不會被回收:

圖片圖片

不過,這種方式只適用于 ThreadLocal生命周期和應用一致 的情況,否則可能會導致 ThreadLocal 變量不被回收,反而導致 OOM!

方案 3:使用 InheritableThreadLocal

如果是 子線程需要繼承父線程的 ThreadLocal 變量,可以使用 InheritableThreadLocal,避免子線程訪問不到 ThreadLocal 變量:

圖片圖片

但它不能解決內(nèi)存泄漏問題,只是拓展了 ThreadLocal 的作用范圍。

總結(jié)

常見錯誤

  • 忘記 remove(),導致 value 無法回收。
  • ThreadLocal 被回收,但 value 還在,導致內(nèi)存泄漏。
  • 線程池使用 ThreadLocal,但不清理,導致長期占用內(nèi)存。

正確做法

  • 在 finally 代碼塊里手動調(diào)用 remove(),避免內(nèi)存泄漏。
  • 避免不必要的 ThreadLocal 實例,盡量復用。
  • 如果一定要在線程池中使用 ThreadLocal,務必 remove() 掉!

尾聲

小王看完這篇文章,恍然大悟:“原來 ThreadLocal 還有這么大的坑,難怪我面試掛了!”

“那你下次再面試,還怕被問到這個問題嗎?”我笑著問。

“怕啥!我還想主動給面試官講一遍,順便聊聊 JVM 內(nèi)存模型!”

責任編輯:武曉燕 來源: 軟件求生
相關(guān)推薦

2021-08-10 09:58:59

ThreadLocal內(nèi)存泄漏

2022-05-09 14:09:23

多線程線程安全

2021-03-04 17:21:49

內(nèi)存檢測泄漏

2022-10-18 08:38:16

內(nèi)存泄漏線程

2024-09-29 08:57:25

2024-10-24 16:51:08

2018-10-25 15:24:10

ThreadLocal內(nèi)存泄漏Java

2023-09-07 17:06:21

@Autowired報錯原因分析

2022-10-25 08:46:26

JSONJavaScript

2020-09-10 07:40:28

ThreadLocal內(nèi)存

2024-09-09 09:41:03

內(nèi)存溢出golang開發(fā)者

2024-03-22 13:31:00

線程策略線程池

2021-02-18 16:53:44

內(nèi)存ThreadLocal線程

2011-05-24 16:39:09

Cfree()

2024-01-30 10:12:00

Java內(nèi)存泄漏

2016-10-31 20:56:57

Javascript閉包內(nèi)存泄漏

2015-05-15 17:29:13

.Netxp系統(tǒng)如何解決

2023-04-19 14:20:49

2022-07-26 07:14:20

線程隔離Thread

2023-12-18 10:45:23

內(nèi)存泄漏計算機服務器
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美一a| 色视频网站在线观看 | 国产一级精品毛片 | 欧美xxxx黑人又粗又长 | 精品国产乱码久久久久久蜜柚 | 免费一区二区在线观看 | 欧美在线观看一区 | 成人在线精品视频 | 一级大片 | 国产日韩欧美一区二区 | av色站 | 国产99小视频 | 美女视频久久 | 久久久久国产精品一区 | 97caoporn国产免费人人 | 婷婷综合五月天 | 国产精品久久国产精品 | 91高清在线观看 | 精品亚洲一区二区三区四区五区高 | 午夜精品久久久久久久星辰影院 | 九色在线视频 | 91精品久久久久久久久久入口 | 日本理论片好看理论片 | 日韩成人一区 | 国产精品久久久久久 | 国产欧美精品区一区二区三区 | 国产精品久久性 | 欧产日产国产精品视频 | 国产美女h视频 | 国产精品免费视频一区 | 欧美美女被c | 在线91| 久久久蜜桃 | 精品国产青草久久久久福利 | 蜜桃一区二区三区在线 | 91欧美| 日韩中文字幕在线视频观看 | 中文字幕视频在线 | 亚洲一区二区av | 色综合久久久 | 91麻豆久久久 |