當前位置:
首頁 > 最新 > Webapp執行reload後內存泄漏之SSLSocketFactory

Webapp執行reload後內存泄漏之SSLSocketFactory

tomcat/jetty是怎麼做reload的呢?

首先, webapp的WEB-INF/lib目錄並不在jvm的classpath內, javaee容器(tomcat/jetty/jboss)是通過自定義的ClassLoader來載入它們的.

而這個ClassLoader,通常的名字就叫做WebappClassLoader, 容器會為每個webapp的每次啟動,都創建一個新的ClassLoader.

「每個webapp」,保證了不同webapp之間的類隔離, 例如有A/B兩個webapp,都使用了DEF類的XXX靜態屬性,那麼在JVM裡面就有2份DEF類,兩份XXX靜態屬性.

「每次啟動」, 是因為容器會先執行一次unload,再執行load,相當於一個新的webapp載入進來.

為什麼reload有泄漏?

首先,什麼是泄漏? 就是你創建了某些對象/數據, 期望它會被GC, 但事實上沒有.

那為啥不被GC呢? 那肯定是被引用了.

虛無的ROOT --> 根ClassLoader --> 一些類的靜態屬性 --> 對象(webapp裡面創建的對象) --> 對象的類 --> WebappClassLoader --> 類 --> 靜態屬性 虛無的ROOT --> 線程組 --> 線程 --> 對象(webapp裡面創建的對象) --> 對象的類 --> WebappClassLoader --> 其他類 --> 靜態屬性

兩條路徑:

webapp內創建的對象,賦值到了根ClassLoader載入的一個類的靜態屬性上.

webapp內創建的線程,reload之後也沒有stop

一時半刻想不出其他路徑了 -_-

靜態屬性的實例

一個非常非常經典的寫法, 忽略Https的無效證書(通常是自簽名證書)

SSLContext sc = SSLContext.getInstance("SSL"); TrustManager[] tmArr = }; sc.init(null, tmArr, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

HttpsURLConnection並非WebappClassLoader載入,而是由根ClassLoader載入.

然後, new X509TrustManager(){}所創建的匿名內部類對象的類,是由WebappClassLoader載入的.

所以呢, 上述代碼就把一個 WebappClassLoader所載入的類的實例,賦值給根ClassLoader載入的類的一個靜態屬性.

最後, 當Webapp被reload時, 老的WebappClassLoader不會被GC, 直至上述代碼再被執行,屬性值被覆蓋.

在一年前, nutz的Http也是這個寫法, 後來改成HttpsURLConnection的實例方法setSSLSocketFactory

類似的代碼存在於很多需要訪問第三方網站的java庫裡面, 例如jpush, socialauth

線程創建導致的泄漏

這種就只能靠自律了… 例如dubbo裡面就建立一堆線程池,然而沒有提供銷毀的方法…

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 推酷 的精彩文章:

提升生活品質的良品
均衡之道—ThinkPad T470 上手體驗
講真,如今的好設計還是離不開數據的支持
小米筆記本 Air 13.3 指紋版上手:新增了指紋識別,圖形處理器能力也更強
SA9527:最好的開始,永遠是現在

TAG:推酷 |

您可能感興趣

C#開發Android應用之WebApp
使用C#開發Android應用之WebApp
前端工程師的新選擇?聊聊WebApp的未來
給你一個webAPP,應該如何運行起來?