The web application [ssms] appears to have started a thread named [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
经过查看许多文档,最终大概可以确认问题来源,这很可能是Tomcat中造成的内存泄漏。应用程序似乎在运行时重新加载其上下文,但是我也不知道为什么。
后来查阅相关的文件,找到了这样的一个
https://wiki.apache.org/tomcat/MemoryLeakProtection
大致的意思是,这很可能意味着使用的框架忘记了清理缓存。例如,在logback中如果出现了这样的问题,Tomcat报告此错误,那么就是因为线程局部变量是根据HTTP工作线程创建的。应用程序虽然还没部署,但HTTP线程仍然存在,这些线程局部变量也存在。这可能导致内存泄漏。
不能卸载[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2])以及将来重用这些线程时出现的一些问题。
不得不说这个上下文加载,是真的挺让人意外了。
【思路1】
有人在类似的问题上做了解答,在一个因为[org.apache.axis.MessageContext] 造成内存泄漏的解答下,它是由Axis产生的,而不是自身出现了问题。但是,上下文启动失败,堆外内存不足,他的意思是通常是PermGen很快会用完。据猜测,也许这个线程本地内存泄漏更严重?提示让我们使用
-xx:+heapDumpOnAutofMemoryError诊断问题。
【思路2】
实在不行,我建议,为了管理上下文重载,在tomcat中使用reloadable=“false”。但是不得不说这样做也是需要付出代价的,因为Java代码或属性的任何更改都不得不重新启动服务器,但为了改掉bug,这也是值得的吧,总比一头蒙强点呀。
【思路3】
这有时候与配置更改也可能有关。如果对Tomcat进行升级,有时候也会出现这种情况。如果是这样的话,那就简单了,打开web.xml文件,如果文件里有< taglib>标签就全部删除,然后更改xmlns:xsi,xmlns:web,schemaLocation,version。
【思路4】
但是其实我又觉得吧,这也不排除是因为有别的文件在此运行过后而未被清理的情况呀,这个时候,也可能会出现此问题。经常在日志中看到以下错误,着实让我有点头大【唉,还没解决掉】,在开发过程中,经常注意到Tomcat由于内存不足而失败,在开发过程中,倘若可以熟练地对后端进行更改,并多次部署应用程序用来时刻查看情况可能能最大程度避免此类问题。但是,最最简单的清理方式是下面这个博客的方案3了吧。
https://blog.csdn.net/ancientear/article/details/86975432
如果真的这样还不行,那么就得检查第三方库。正常情况下,库应该趁着程序关闭或者重启的时候,提供一些机制自动清理线程。然而如果没提供。最糟糕的情况就是自己去实现了吧。关键是我也尚未学会呀【一个晕乎乎的脑袋瓜子】,这已经超出我能力范围了。。。
如果真的更想了解一下这个情况,推荐大家去看文档。
http://www.ehcache.org/documentation/2.8/operations/shutdown.html
【思路5】
有一个Spring论坛指出,在Tomcat和web application post forum.springsource.org之间的交互中,此报错信息是一个错误的特性,它指出“不幸的是,没有公共API来主动删除依赖垃圾收集的线程局部变量。这是影响所有创建线程本地的应用程序的原因。
【思路6】
也有位叫做George Georgovassilis的人说,
“George Georgovassilis”看起来像是在没有适当事务的情况下与数据库通信。确保事务管理配置正确,并且不存在不在@transactional注释下运行的DAO调用路径。当在控制器级别配置事务管理,但在计时器中调用DAO或使用@postconstruct注释时,很容易发生这种情况。
【思路7】
搜罗来的解决方案有这么一个,在cdi@applicationscoped bean中向@predstroy方法添加了以下内容,当关闭tomcat时,它将会清除线程局部变量。转自Howard(如下图)
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package pf;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Administrator
*
* google-gson issue # 402: Memory Leak in web application; comment # 25
* https://code.google.com/p/google-gson/issues/detail?id=402
*/
public class ThreadLocalImmolater {
final Logger logger = LoggerFactory.getLogger(ThreadLocalImmolater.class);
Boolean debug;
public ThreadLocalImmolater() {
debug = true;
}
public Integer immolate() {
int count = 0;
try {
final Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
final Field inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals");
inheritableThreadLocalsField.setAccessible(true);
for (final Thread thread : Thread.getAllStackTraces().keySet()) {
count += clear(threadLocalsField.get(thread));
count += clear(inheritableThreadLocalsField.get(thread));
}
logger.info("immolated " + count + " values in ThreadLocals");
} catch (Exception e) {
throw new Error("ThreadLocalImmolater.immolate()", e);
}
return count;
}
private int clear(final Object threadLocalMap) throws Exception {
if (threadLocalMap == null)
return 0;
int count = 0;
final Field tableField = threadLocalMap.getClass().getDeclaredField("table");
tableField.setAccessible(true);
final Object table = tableField.get(threadLocalMap);
for (int i = 0, length = Array.getLength(table); i < length; ++i) {
final Object entry = Array.get(table, i);
if (entry != null) {
final Object threadLocal = ((WeakReference)entry).get();
if (threadLocal != null) {
log(i, threadLocal);
Array.set(table, i, null);
++count;
}
}
}
return count;
}
private void log(int i, final Object threadLocal) {
if (!debug) {
return;
}
if (threadLocal.getClass() != null &&
threadLocal.getClass().getEnclosingClass() != null &&
threadLocal.getClass().getEnclosingClass().getName() != null) {
logger.info("threadLocalMap(" + i + "): " +
threadLocal.getClass().getEnclosingClass().getName());
}
else if (threadLocal.getClass() != null &&
threadLocal.getClass().getName() != null) {
logger.info("threadLocalMap(" + i + "): " + threadLocal.getClass().getName());
}
else {
logger.info("threadLocalMap(" + i + "): cannot identify threadlocal class name");
}
}
}
如若路过的大神们有更好的方法,请一定一定告知,不胜感激。