Catalina.out内存泄漏错误

我仍然在tomcat/logs/catalina.out看到此错误。

 Dec 29, 2011 4:04:36 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads SEVERE: The web application [/LoggingMonitor] appears to have started a thread named [Timer-1] but has failed to stop it. This is very likely to create a memory leak. Dec 29, 2011 4:04:36 PM org.apache.coyote.http11.Http11Protocol destroy INFO: Stopping Coyote HTTP/1.1 on http-8180 

是否值得考虑,如果是,我该如何纠正?

这可能没什么大不了的(只需杀掉-9或其他东西)并且很容易修复。 只需找出在/ LoggingMonitor上下文中运行的webapp然后grep其代码库…

 new Timer(); 

……并用……替换它们

 new Timer( true ); 

默认情况下,java.util.Timer不在守护程序线程中运行。 您需要Web应用程序中的任何计时器在守护程序线程上运行(否则容器无法正常关闭,因为它正在等待Timer线程结束,它从未执行过)。 找到所有“新的Timer()”调用并用“new Timer(true)”替换它们,并且应该停止记录投诉。

花一些时间在JavaDocs中学习一些关于守护进程与非守护进程的内容: http : //docs.oracle.com/javase/1.4.2/docs/api/java/util/Timer.html

当我在webapps中工作时,如果我最终做了自己的multithreading,我总是使用守护进程线程。 使用java.util.concurrent中的工具,这变得非常罕见(必须做我自己的线程化的东西)。

最后,为了记录,我讨厌java.util.Timer并始终建议使用ScheduledExecutor之类的东西来执行定期的重复性任务。 它很容易搞砸Timer并取出它执行的Tread,守护进程或其他方式。

如果您在取消部署/重新部署应用程序时总是停止Tomcat,那么这条消息并不是什么大问题否则这些操作会导致内存泄漏,这对于生产来说尤为重要。

名为“Timer-#”的线程由Bob Kuhar建议的java.util.Timer(可能由其他类)创建,但是对您自己的代码库进行grepping可能还不够,并且确保使用守护程序线程不能消除该消息( Tom Hawtin的评论是正确的)。

当我得到该消息时,它是由我的代码的传递依赖产生的,正是由使用守护程序线程的Apache Commons Pool v1.3的类GenericObjectPool产生的(参见源代码 )。 要找到实例化Timer的类,我必须在每个Timer类的构造函数中放置一个breackpoint然后检查调用堆栈。 为了解决这个问题,我不得不升级库(较新版本的Commons Pool不使用该Timer)。

当您控制实例化线程的代码时,您可以通过确保在应用程序停止时停止线程来解决问题。 使用守护程序线程是一种很好的做法,但还不够,因为守护程序线程只有在关闭Tomcat时才会自动死亡,而在取消部署应用程序时则不会自动死亡。

在更一般的情况下,当您不知道是谁创建了讨厌的线程时,请检查Java应用程序中的查找线程创建源和检测谁创建了线程(w.Eclipse) 。

UPDATE

一种完全不同的方法是使用非常有趣的泄漏预防监听器 。 另请阅读该作者关于classloader泄漏的其他post。