由于Tomcat中的孤立线程,我遇到了内存泄漏。特别是,看起来Guice和JDBC驱动程序并没有关闭线程。
Aug 8, 2012 4:09:19 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [com.google.inject.internal.util.$Finalizer] but has failed to stop it. This is very likely to create a memory leak.
Aug 8, 2012 4:09:19 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.我知道这类似于其他问题(例如this one),但在我的情况下,“不用担心它”的答案是不够的,因为它给我带来了问题。我有CI服务器,它会定期更新此应用程序,重新加载6-10次后,CI服务器将挂起,因为Tomcat内存不足。
我需要能够清除这些孤立线程,这样我才能更可靠地运行CI服务器。任何帮助都将不胜感激!
发布于 2013-05-10 01:33:58
我刚刚自己处理了这个问题。与其他一些答案相反,我不建议发出t.stop()命令。这个方法已经被弃用了,这是有充分理由的。有关此操作的参考Oracle's reasons。
然而,有一种解决方案可以消除此错误,而不需要求助于t.stop()……
您可以使用@Oso提供的大部分代码,只需替换以下部分
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for(Thread t:threadArray) {
if(t.getName().contains("Abandoned connection cleanup thread")) {
synchronized(t) {
t.stop(); //don't complain, it works
}
}
}使用MySQL驱动程序提供的以下方法替换它:
try {
AbandonedConnectionCleanupThread.shutdown();
} catch (InterruptedException e) {
logger.warn("SEVERE problem cleaning up: " + e.getMessage());
e.printStackTrace();
}这应该会正确地关闭线程,并且错误应该会消失。
发布于 2012-09-16 13:16:35
我也遇到过同样的问题,正如Jeff所说,“不用担心”的方法并不可取。
我做了一个在上下文关闭时停止挂起线程的ServletContextListener,然后在web.xml文件上注册了这样的ContextListener。
我已经知道停止线程不是一个优雅的方法来处理它们,但否则服务器在两到三次部署后仍然会崩溃(并不总是可以重启应用服务器)。
我创建的类是:
public class ContextFinalizer implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(ContextFinalizer.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
Enumeration<Driver> drivers = DriverManager.getDrivers();
Driver d = null;
while(drivers.hasMoreElements()) {
try {
d = drivers.nextElement();
DriverManager.deregisterDriver(d);
LOGGER.warn(String.format("Driver %s deregistered", d));
} catch (SQLException ex) {
LOGGER.warn(String.format("Error deregistering driver %s", d), ex);
}
}
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for(Thread t:threadArray) {
if(t.getName().contains("Abandoned connection cleanup thread")) {
synchronized(t) {
t.stop(); //don't complain, it works
}
}
}
}
}创建类后,在web.xml文件中注册它:
<web-app...
<listener>
<listener-class>path.to.ContextFinalizer</listener-class>
</listener>
</web-app>发布于 2013-09-26 20:09:42
最不具侵入性的解决方法是从MySQL类加载器外部的代码强制初始化webapp驱动程序。
在tomcat/conf/server.xml中,修改(在Server元素中):
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />至
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"
classesToInitialize="com.mysql.jdbc.NonRegisteringDriver" />带有mysql-
com.mysql.cj.jdbc.NonRegisteringDriver代替这里假设您将tomcat驱动程序放到了tomcat目录中,而不是放在Webapp.war的WEB-INF/lib目录中,因为重点是在MySQL之前独立于您的WEB应用程序加载驱动程序。
参考文献:
https://stackoverflow.com/questions/11872316
复制相似问题