最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ThreadLocal的內(nèi)存泄露問題

 更新時間:2023年03月30日 09:46:06   作者:小孫的Blog  
這篇文章主要介紹了Java中ThreadLocal的內(nèi)存泄露問題,以及為什么會出現(xiàn)內(nèi)存泄漏,感興趣的小伙伴可以參考閱讀

ThreadLocal的內(nèi)部實現(xiàn)

在每一個線程Thread對象中,都維護了一個ThreadLocalMap對象。

 ThreadLocalMap中又維護了一個k v 形式的Entry對象,key指向了當前ThreadLocal對象,value就是我們實際在ThreadLocal中存儲的值。

注意,這里的Entry中的key存放是ThreadLocal的弱引用。

 實現(xiàn)指的是強引用,虛線指的是弱引用。

 其實際上,ThreaLocal本身是不存儲值的,我們在使用其對應的set、get方法時,都是操作的其對應的ThreadLocalMap對象。

為什么會出現(xiàn)內(nèi)存泄露?

從上述可以看到,在Entry中的key存儲的ThreadLocal的弱引用。

弱引用在發(fā)生GC時,就會被垃圾回收掉,具體可以參考JVM相關(guān)的知識。

所以,在當前線程正在運行的時候,發(fā)生GC時,在ThreadLocal對象沒有被其它地方強引用時,key指向ThreadLocal的虛引用就會立即斷開(被垃圾回收掉),這時,就會出現(xiàn)ThreadLocalMap中存在key為null的Entry,只要當前線程不結(jié)束,該ThreadLocalMap對象就會一直存在,永遠無法回收,因為此時還存在一條強引用的鏈路,從圖中也可以發(fā)現(xiàn):

Current Thread Reference --> Current Thread --> ThreadLocalMap --> EntryValue --> Object

所以這個時候就造成了內(nèi)存泄露。

Entry對象的key為什么要使用弱引用,有什么好處?

在上述所說的問題中,即使ThreadLocalMap中存在key為null的Entry,但是該Entry的value值并不會因為GC而被回收(value存本身就存著一個強引用的對象),所以就導致了該對象不會被回收掉而出現(xiàn)了內(nèi)存泄露。

其實,ThreadLocalMap在設計時就考慮到了這個方面,它也采取了一些措施來避免這種key為null,而value不為null的對象占用內(nèi)存,在我們調(diào)用ThreadLocal的set、get、remove方法時,都會將這些key為null的對象清空掉,避免因為這種情況而導致內(nèi)存泄露。

這也就是為什么key要存儲弱引用的原因。

假設如果存儲的強引用,我們斷開ThreadLocal Reference —> ThreadLocal的引用,會發(fā)現(xiàn)key強引用了ThreadLocal,導致該對象永遠無法被GC。

但是,即使上述提供了避免內(nèi)存泄露的措施,但是不能完全避免,比如以下的情況:

  • 分配了ThreadLocal對象,但是并沒有執(zhí)行其get、set、remove方法,導致不能有效的清除null對象;
  • 使用線程池的情況下,使用完ThreadLocal一定要使用remove方法即時清理,因為ThreadLocal是屬于某個線程的,而在使用線程池的情況下,這些線程都是可重復利用、存活時間長的線程,如果在使用過程中不僅從即使的remove,那么不僅會造成內(nèi)存泄露的問題,還會引發(fā)一些功能邏輯問題,比如,B請求可能和A請求分配到了線程池中的同一個線程,那么它們拿到的ThreadLocal就是一樣的。

 set

cleanSomeSlots

get

關(guān)于弱引用的一些知識補充

學習的過程中想到了一個問題,弱引用會不會導致運行過程中GC清除key,導致找不到對應的value?

可能是當時對弱引用的理解不夠熟,所以產(chǎn)生了這個問題,如下面的代碼。

public class TestDemo {

    static ThreadLocal threadLocal = new ThreadLocal();

    public static void main(String[] args) {

        threadLocal.set("demo");
        System.gc();
        System.out.println(threadLocal.get());	// demo

    }
}

為什么還獲取到值,不是說在發(fā)現(xiàn)一次GC,弱引用就會被清除掉嗎?

糊涂了。

弱引用只有在該對象沒有被其它地方強引用的時候,才會被GC。

上述的原因就是因為,很明顯,ThreadLocal對象除了被key弱引用,還由一個Reference強引用指向它,所以肯定不會被GC。

如果是這樣,那下一次GC,這個對象就被干掉了。

舉一個簡單的例子,幫助理解:

WeakReference<User> userWeakReference = new WeakReference<User>(new User("jack"));

System.out.println(userWeakReference.get() == null);  // false

System.gc();

System.out.println(userWeakReference.get() == null);  // true

很明顯,GC的時候直接清除了這個弱引用對象。

 userWeakReference.get(), 如果此方法為空, 那么說明weakReference指向的對象已經(jīng)被回收了。

WeakReference<User> userWeakReference = new WeakReference<User>(new User("jack"));
User jack = userWeakReference.get();
System.out.println(userWeakReference.get() == null);  // false

System.gc();

System.out.println(userWeakReference.get() == null);  // false

 當我們添加了一個強引用來指向它的時候,該對象并不會被gc清除(弱引用還在)。

 到此這篇關(guān)于ThreadLocal的內(nèi)存泄露問題的文章就介紹到這了,更多相關(guān)ThreadLocal內(nèi)存泄露內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

鄱阳县| 阿勒泰市| 长葛市| 哈尔滨市| 炎陵县| 澳门| 年辖:市辖区| 阿坝县| 天全县| 苗栗市| 隆尧县| 浙江省| 宁蒗| 田阳县| 合阳县| 东乌珠穆沁旗| 保定市| 客服| 辽阳市| 内黄县| 长丰县| 台湾省| 库车县| 温宿县| 荣昌县| 汶上县| 景德镇市| 无锡市| 三门峡市| 瓦房店市| 蓝田县| 台东县| 通城县| 都安| 福清市| 时尚| 天柱县| 云霄县| 马边| 浦东新区| 奉贤区|