Tomcat Guice/JDBC 内存泄漏
Tomcat Guice/JDBC 内存泄漏
我在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.
我知道这与其他问题类似(例如此问题),但在我的情况下,“不要担心它”这样的回答不够,因为它给我带来了问题。我有一个CI服务器定期更新这个应用程序,经过6到10次重载后,CI服务器将挂起,因为Tomcat已经用完了内存。
我需要能够清理这些孤立的线程,以便我可以更可靠地运行我的CI服务器。任何帮助将不胜感激!
admin 更改状态以发布 2023年5月22日
我曾经遇到了同样的问题,正如 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) { Enumerationdrivers = 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 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 文件中:
path.to.ContextFinalizer
我刚刚自己解决了这个问题。与其他答案不同,我不建议发出t.stop()
命令。这种方法已经过时,有充分的理由。参考Oracle的原因。
但是有一种方法可以在不需要使用t.stop()
的情况下解决此错误...
您可以使用@Oso提供的大部分代码,只需更换以下部分
SetthreadSet = 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(); }
这应该可以正确关闭线程,并且错误应该会消失。