欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

在每一個(gè)線程Thread對象中,都維護(hù)了一個(gè)ThreadLocalMap對象。

 ThreadLocalMap中又維護(hù)了一個(gè)k v 形式的Entry對象,key指向了當(dāng)前ThreadLocal對象,value就是我們實(shí)際在ThreadLocal中存儲(chǔ)的值。

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

 實(shí)現(xiàn)指的是強(qiáng)引用,虛線指的是弱引用。

 其實(shí)際上,ThreaLocal本身是不存儲(chǔ)值的,我們在使用其對應(yīng)的set、get方法時(shí),都是操作的其對應(yīng)的ThreadLocalMap對象。

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

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

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

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

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

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

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

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

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

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

假設(shè)如果存儲(chǔ)的強(qiáng)引用,我們斷開ThreadLocal Reference —> ThreadLocal的引用,會(huì)發(fā)現(xiàn)key強(qiáng)引用了ThreadLocal,導(dǎo)致該對象永遠(yuǎn)無法被GC。

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

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

 set

cleanSomeSlots

get

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

學(xué)習(xí)的過程中想到了一個(gè)問題,弱引用會(huì)不會(huì)導(dǎo)致運(yùn)行過程中GC清除key,導(dǎo)致找不到對應(yīng)的value?

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

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,弱引用就會(huì)被清除掉嗎?

糊涂了。

弱引用只有在該對象沒有被其它地方強(qiáng)引用的時(shí)候,才會(huì)被GC。

上述的原因就是因?yàn)?,很明顯,ThreadLocal對象除了被key弱引用,還由一個(gè)Reference強(qiáng)引用指向它,所以肯定不會(huì)被GC。

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

舉一個(gè)簡單的例子,幫助理解:

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的時(shí)候直接清除了這個(gè)弱引用對象。

 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

 當(dāng)我們添加了一個(gè)強(qiáng)引用來指向它的時(shí)候,該對象并不會(huì)被gc清除(弱引用還在)。

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

相關(guān)文章

  • Idea中g(shù)it的使用小結(jié)

    Idea中g(shù)it的使用小結(jié)

    這篇文章主要介紹了Idea中g(shù)it的使用小結(jié),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-01-01
  • Elasticsearch?mapping?概念及自動(dòng)創(chuàng)建示例

    Elasticsearch?mapping?概念及自動(dòng)創(chuàng)建示例

    這篇文章主要為大家介紹了Elasticsearch?mapping?概念及自動(dòng)創(chuàng)建示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Java實(shí)現(xiàn)統(tǒng)計(jì)文檔中關(guān)鍵字出現(xiàn)的次數(shù)

    Java實(shí)現(xiàn)統(tǒng)計(jì)文檔中關(guān)鍵字出現(xiàn)的次數(shù)

    這篇文章主要為大家分享了利用Java語言實(shí)現(xiàn)統(tǒng)計(jì)關(guān)鍵字在文檔中出現(xiàn)的次數(shù)的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-05-05
  • Java線程的生命周期命名與獲取代碼實(shí)現(xiàn)

    Java線程的生命周期命名與獲取代碼實(shí)現(xiàn)

    這篇文章主要介紹了Java線程的生命周期命名與獲取代碼實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Java實(shí)現(xiàn)獲取cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)等信息的方法示例

    Java實(shí)現(xiàn)獲取cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)等信息的方法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)獲取cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)等信息的方法,涉及java使用第三方j(luò)ar包針對本機(jī)硬件的cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)信息等的讀取相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06
  • springboot 緩存@EnableCaching實(shí)例

    springboot 緩存@EnableCaching實(shí)例

    這篇文章主要介紹了springboot 緩存@EnableCaching實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Idea工具中創(chuàng)建 SpringBoot工程及入門詳解

    Idea工具中創(chuàng)建 SpringBoot工程及入門詳解

    這篇文章主要介紹了Idea工具中創(chuàng)建 SpringBoot工程及入門分析詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • 一文詳解Spring是怎樣處理循環(huán)依賴的

    一文詳解Spring是怎樣處理循環(huán)依賴的

    循環(huán)依賴簡單理解就是A,B 兩個(gè)bean相互依賴,A依賴B,B依賴A,A->B、B->A大概就是這樣,這篇文章主要介紹了Spring是怎樣處理循環(huán)依賴的,文中通過代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2024-01-01
  • Spring源碼解析后置處理器梳理總結(jié)

    Spring源碼解析后置處理器梳理總結(jié)

    這篇文章主要介紹了Spring源碼解析后置處理器梳理總結(jié),在前面幾篇文章中梳理了Spring中bean的創(chuàng)建過程,在這個(gè)過程中各式各樣的后置處理器發(fā)揮了不同的作用,可以說后置處理器貫穿了bean的實(shí)例化以及初始化過程
    2022-07-07
  • Java程序初始化啟動(dòng)自動(dòng)執(zhí)行的三種方式

    Java程序初始化啟動(dòng)自動(dòng)執(zhí)行的三種方式

    這篇文章主要介紹了Java程序初始化啟動(dòng)自動(dòng)執(zhí)行的三種方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評論