Threads are going to be renewed over time to try and avoid a probable memory leak.

wangbiao007發表於2020-04-05

記錄一次記憶體洩漏問題的解決
問題現象:啟動tomcat後,過幾個小時,線上的工程就會停止執行了,日誌裡面就會報下面這樣的錯誤

13-Aug-2019 12:51:27.248 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@4a9cfa60]) and a value of type [com.daichao.loans.api.common.AuthenticationType] (value [TOKEN]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

 

這個是由於類載入器洩漏導致的的,從上面的問題可以看出來當應用結束的時候,想釋放AuthenticationType,但是卻釋放不了,為什麼釋放不了呢?
先看程式碼:
先在LoginUtils裡面定義了一個ThreadLocal

public static final ThreadLocal<AuthenticationType> authenticationType 
	       = new ThreadLocal<AuthenticationType>();

再到SystemController類裡設定值

LoginUtils.authenticationType.set(authenticationType);

最後再到MyRealm裡取值

AuthenticationType authTypeClass = LoginUtils.authenticationType.get();

tomcat有一個執行緒池,當有外部請求來的時候,會從執行緒池裡面取出一個執行緒來處理請求,ThradLocal引用了AuthenticationType,執行緒對ThradLocal設值,相當於將AuthenticationType繫結到了這個執行緒,當應用結束了,想去回收AuthenticationType的classloader,即使已經沒有其他地方對AuthenticationType的引用了,但執行緒還沒有結束,這個執行緒還對AuthenticationType有引用,tomcat回收資源的時候,發現AuthenticationType回收不了,就會出現記憶體洩漏的警告。

最後的解決方法是:當應用結束的時候手動釋放ThreadLocal裡面的AuthenticationType

try{
    AuthenticationType authTypeClass = LoginUtils.authenticationType.get();
}finally{
    LoginUtils.authenticationType.remove();
}

參考文章:https://blog.csdn.net/u010619243/article/details/62899033

相關文章