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

實例詳解Java中ThreadLocal內(nèi)存泄露

 更新時間:2016年08月14日 10:59:16   投稿:daisy  
這一篇文章我們來分析一個Java中ThreadLocal內(nèi)存泄露的案例。分析問題的過程比結(jié)果更重要,理論結(jié)合實際才能徹底分析出內(nèi)存泄漏的原因。

案例與分析

問題背景

在 Tomcat 中,下面的代碼都在 webapp 內(nèi),會導(dǎo)致WebappClassLoader泄漏,無法被回收。

public class MyCounter {
    private int count = 0;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class MyThreadLocal extends ThreadLocal<MyCounter> {
}

public class LeakingServlet extends HttpServlet {
    private static MyThreadLocal myThreadLocal = new MyThreadLocal();

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        MyCounter counter = myThreadLocal.get();
        if (counter == null) {
            counter = new MyCounter();
            myThreadLocal.set(counter);
        }

        response.getWriter().println(
                "The current thread served this servlet " + counter.getCount()
                        + " times");
        counter.increment();
    }
}

上面的代碼中,只要LeakingServlet被調(diào)用過一次,且執(zhí)行它的線程沒有停止,就會導(dǎo)致WebappClassLoader泄漏。每次你 reload 一下應(yīng)用,就會多一份WebappClassLoader實例,最后導(dǎo)致 PermGen OutOfMemoryException。

解決問題

現(xiàn)在我們來思考一下:為什么上面的ThreadLocal子類會導(dǎo)致內(nèi)存泄漏?

WebappClassLoader

首先,我們要搞清楚WebappClassLoader是什么鬼?

對于運行在 Java EE容器中的 Web 應(yīng)用來說,類加載器的實現(xiàn)方式與一般的 Java 應(yīng)用有所不同。不同的 Web 容器的實現(xiàn)方式也會有所不同。以 Apache Tomcat 來說,每個 Web 應(yīng)用都有一個對應(yīng)的類加載器實例。該類加載器也使用代理模式,所不同的是它是首先嘗試去加載某個類,如果找不到再代理給父類加載器。這與一般類加載器的順序是相反的。這是 Java Servlet 規(guī)范中的推薦做法,其目的是使得 Web 應(yīng)用自己的類的優(yōu)先級高于 Web 容器提供的類。這種代理模式的一個例外是:Java 核心庫的類是不在查找范圍之內(nèi)的。這也是為了保證 Java 核心庫的類型安全。

也就是說WebappClassLoader是 Tomcat 加載 webapp 的自定義類加載器,每個 webapp 的類加載器都是不一樣的,這是為了隔離不同應(yīng)用加載的類。

那么WebappClassLoader的特性跟內(nèi)存泄漏有什么關(guān)系呢?目前還看不出來,但是它的一個很重要的特點值得我們注意:每個 webapp 都會自己的WebappClassLoader,這跟 Java 核心的類加載器不一樣。

我們知道:導(dǎo)致WebappClassLoader泄漏必然是因為它被別的對象強引用了,那么我們可以嘗試畫出它們的引用關(guān)系圖。等等!類加載器的作用到底是啥?為什么會被強引用?

類的生命周期與類加載器

要解決上面的問題,我們得去研究一下類的生命周期和類加載器的關(guān)系。

跟我們這個案例相關(guān)的主要是類的卸載:

在類使用完之后,如果滿足下面的情況,類就會被卸載:

      1、該類所有的實例都已經(jīng)被回收,也就是 Java 堆中不存在該類的任何實例。

      2、加載該類的ClassLoader已經(jīng)被回收。

      3、該類對應(yīng)的java.lang.Class對象沒有任何地方被引用,沒有在任何地方通過反射訪問該類的方法。

如果以上三個條件全部滿足,JVM 就會在方法區(qū)垃圾回收的時候?qū)︻愡M(jìn)行卸載,類的卸載過程其實就是在方法區(qū)中清空類信息,Java 類的整個生命周期就結(jié)束了。

由Java虛擬機(jī)自帶的類加載器所加載的類,在虛擬機(jī)的生命周期中,始終不會被卸載。Java虛擬機(jī)自帶的類加載器包括根類加載器、擴(kuò)展類加載器和系統(tǒng)類加載器。Java虛擬機(jī)本身會始終引用這些類加載器,而這些類加載器則會始終引用它們所加載的類的Class對象,因此這些Class對象始終是可觸及的。

由用戶自定義的類加載器加載的類是可以被卸載的。

注意上面這句話,WebappClassLoader如果泄漏了,意味著它加載的類都無法被卸載,這就解釋了為什么上面的代碼會導(dǎo)致 PermGen OutOfMemoryException。

關(guān)鍵點看下面這幅圖

 

我們可以發(fā)現(xiàn):類加載器對象跟它加載的 Class 對象是雙向關(guān)聯(lián)的。這意味著,Class 對象可能就是強引用WebappClassLoader,導(dǎo)致它泄漏的元兇。

引用關(guān)系圖

理解類加載器與類的生命周期的關(guān)系之后,我們可以開始畫引用關(guān)系圖了。(圖中的LeakingServlet.classmyThreadLocal引用畫的不嚴(yán)謹(jǐn),主要是想表達(dá)myThreadLocal是類變量的意思)

下面,我們根據(jù)上面的圖來分析WebappClassLoader泄漏的原因。

      1、LeakingServlet持有staticMyThreadLocal,導(dǎo)致myThreadLocal的生命周期跟LeakingServlet類的生命周期一樣長。意味著myThreadLocal不會被回收,弱引用形同虛設(shè),所以當(dāng)前線程無法通過ThreadLocalMap的防護(hù)措施清除counter的強引用。

      2、強引用鏈:thread -> threadLocalMap -> counter -> MyCounter.class -> WebappClassLocader,導(dǎo)致WebappClassLoader泄漏。

總結(jié)

內(nèi)存泄漏是很難發(fā)現(xiàn)的問題,往往由于多方面原因造成。ThreadLocal由于它與線程綁定的生命周期成為了內(nèi)存泄漏的??停杂胁簧骶歪劤纱蟮?。本文只是對一個特定案例的分析,若能以此舉一反三,那便是極好的。希望本文對大家能有所幫助。

相關(guān)文章

  • SpringBoot整合EasyExcel實現(xiàn)Excel表格導(dǎo)出功能

    SpringBoot整合EasyExcel實現(xiàn)Excel表格導(dǎo)出功能

    這篇文章主要介紹了SpringBoot整合EasyExcel實現(xiàn)Excel表格導(dǎo)出功能,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-07-07
  • BeanUtils.copyProperties()參數(shù)的賦值順序說明

    BeanUtils.copyProperties()參數(shù)的賦值順序說明

    這篇文章主要介紹了BeanUtils.copyProperties()參數(shù)的賦值順序說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot中@GetMapping注解的使用

    SpringBoot中@GetMapping注解的使用

    @GetMapping注解是Spring Boot中最常用的注解之一,它可以幫助開發(fā)者定義和處理HTTP GET請求,本文就來介紹一下SpringBoot中@GetMapping注解的使用,感興趣的可以了解一下
    2023-10-10
  • Java字符串查找的三種方式

    Java字符串查找的三種方式

    本篇文章給大家整理了關(guān)于Java字符串查找的三種方式,并把其中需要留意的地方做了標(biāo)注,一起參考學(xué)習(xí)下。
    2018-03-03
  • java.lang.OutOfMemoryError: Java heap space錯誤的問題解決

    java.lang.OutOfMemoryError: Java heap space錯誤

    本文主要介紹了java.lang.OutOfMemoryError: Java heap space錯誤的問題解決,包括內(nèi)存泄漏、數(shù)據(jù)過大和JVM堆大小配置不足,提供了解決方法,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • SpringBoot內(nèi)部外部配置文件加載順序解析

    SpringBoot內(nèi)部外部配置文件加載順序解析

    這篇文章主要介紹了SpringBoot內(nèi)部外部配置文件加載順序解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • JVM之內(nèi)存分配和回收機(jī)制

    JVM之內(nèi)存分配和回收機(jī)制

    本篇主要介紹JVM內(nèi)存分配和回收策略,內(nèi)容主要節(jié)選自《深入理解java虛擬機(jī)》,需要的朋友可以參考下
    2023-05-05
  • 23種設(shè)計模式(17)java命令模式

    23種設(shè)計模式(17)java命令模式

    這篇文章主要為大家詳細(xì)介紹了23種設(shè)計模式之java命令模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • springboot整合jasypt的詳細(xì)過程

    springboot整合jasypt的詳細(xì)過程

    這篇文章主要介紹了springboot整合jasypt的詳細(xì)過程,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-02-02
  • SpringBoot集成slf4j日志配置的方法

    SpringBoot集成slf4j日志配置的方法

    本文主要介紹了SpringBoot集成slf4j日志配置的方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論

福泉市| 土默特左旗| 博客| 营山县| 剑川县| 株洲县| 宿迁市| 昆山市| 玛纳斯县| 定陶县| 保定市| 获嘉县| 崇明县| 都匀市| 疏勒县| 舟山市| 乐都县| 咸阳市| 玉屏| 厦门市| 隆回县| 威远县| 新宁县| 富阳市| 屏山县| 哈尔滨市| 新郑市| 无棣县| 连云港市| 永春县| 赤城县| 广安市| 翼城县| 博野县| 浏阳市| 邵阳县| 香河县| 珠海市| 肇州县| 铅山县| 安龙县|