ThreadLocal是否會引發內存泄露的分析 good


這篇文章,主要解決一下疑惑:
1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟會不會被回收?
2. 弱引用什么情況下回收?
3. JAVA的ThreadLocal和在什么情況下會內存泄露?
 
帶着這些疑問,自己模擬了一下ThreadLocal.ThreadLocalMap的結構,先展示下自己涉及的結構:
自己實現一個simple的ThreadLocalMap,里面用一個entry用來存放由自己模擬的ThreadLocal調用set方法set進去的值。
並且和JDK的ThreadLocalMap一樣里面Entry對象的key用weakReference封裝。
 
Main方法如下:

  
 
設置運行參數:
-verbose:gc  
 
看輸出結果:

這里我已經模擬出了內存泄露的問題,可以看到FULL GC以后,內存還是被占用,且仔細觀察可以看到,這個map中的Key已經有為null了。
換句話說你通過Key已經不能獲取到value了,當然map.get(null)也是可以的,
不過JAVA里的ThreadLocal不會這么去做,因為Map中key==null的元素可能不唯一。
從我的Main方法中可以看到,我有th=null的操作,但是還是有內存泄露,原因稍后分析。
但有一點可以確定:th=null在這里不能如我們想象的將ThreadLocal th 的引用釋放掉后,里面的key,value對象也釋放,可能會有疑問我這里持有了ThreadLocalMap的引用tm所以不會回收,但實際上,手動設置JAVA的ThreadLocal為null時,當前線程任然持有ThreadLocalMap的引用,所以不會回收我這里和JAVA是類似的。
 
回到剛開始提出的3個問題,一一解答:
1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟會不會被回收?
     會被回收,如上圖所示。key 已經有null的情況了。第一個Key不為null,原因在第二點。在經歷過FULL GC后 所有的key都被回收了。
2. 弱引用什么情況下回收?
     弱引用在GC(包括MinitorGC和Full GC)時,被掃描到就會被回收,但是有一個前提,該弱引用在外部沒有被引用到(這個時候外部的引用等於強引用)。
     換句話說,如果我main方法中持有一個key的引用,哪怕他put進Map后被設置為弱引用的,也不會被回收。見下圖:

 

GC 日志:

 
     
3. JAVA的ThreadLocal和在什么情況下會內存泄露?
   答案是不會,原因如下圖,在我們調用ThreadLocal.set()的時候,會做一個將Key== null 的元素清理掉的工作,具體做法是:
     第一步:ThreadLocalMap 拿threadLocalHashCode與長度減一相與,求出哈希表的位置下圖中的 i 。
     第二步:編列Entry,如果找到key相等的,覆蓋原值! 或者找到key==null的,將值set進去,並且將遍歷時路過的key==null的元素和他的value都置為null,,釋放內存。
     第三步:最后一個if條件時,做rehash的動作,即:將Entry里的元素重新計算一下Hash值,放到合適的位置去,猜想是為了加快下次訪問的速度。


 
總結:
     從這里看出,JAVA的ThreadLocal對Key使用到了弱引用,但是為了保證不再內存泄露,在每次set.get的時候主動對key==null的entry做遍歷回收。
     雖然不會造成內存泄露,但是因為只有在每次set,get的時候才會對entry做key==null的判斷,從而釋放內存,所以可能使大對象在內存中存活很長一段時間,從而占用內存。
     所以,我們在使用完ThreadLocal里的對象后最好能手動remove一下,或者至少調用下ThreadLocal.set(null)。
     值得注意的是ThreadLocal中的key是當前當前ThreadLocal自己,就像上面模擬的外部持有強引用的情況,ThreadLocal.ThreadLocalMap中的key==null情況很少出現,因為,大部分情況ThreadLocal是以單例模式一直存在的。

 

  • 大小: 18.7 KB
  • 大小: 15.9 KB
  • 大小: 26.8 KB
  • 大小: 26.4 KB
  • 大小: 39.3 KB
  • 大小: 26.2 KB
 
http://liuinsect.iteye.com/blog/1827012


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM