记录一次内存泄漏问题的解决
问题现象:启动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

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐