我仍然在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
是否值得考虑,如果是,我该如何纠正?
答案 0 :(得分:3)
这可能没什么大不了的(只需杀掉-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中工作时,如果我最终执行任何自己的多线程,我总是使用守护程序线程。使用java.util.concurrent中的工具,这变得非常罕见(必须自己进行线程处理)。
最后,为了记录,我讨厌java.util.Timer并且总是建议使用ScheduledExecutor之类的东西来做周期性的重复性任务。它很容易搞砸Timer并取出它在守护进程或其他方面执行的Tread。
答案 1 :(得分:2)
该消息不是什么大问题如果你在取消部署/重新部署应用程序时总是停止Tomcat,否则这些操作会导致内存泄漏, 是一个大问题,特别是在生产中。
名为“Timer-#”的线程由java.util.Timer(可能由其他类)创建,如Bob Kuhar所示,但是对您自己的代码库进行grepping可能还不够,并确保您使用守护程序线程消除那条消息(Tom Hawtin的评论是正确的)。
当我收到该消息时,它是由我的代码的传递依赖产生的,正是由使用守护程序线程的Apache Commons Pool v1.3的类GenericObjectPool
产生的(参见{{ 3}})。要找到实例化Timer的类,我必须在每个Timer类的构造函数中放置一个breackpoint然后检查调用堆栈。为了解决这个问题,我不得不升级库(较新版本的Commons Pool不使用该计时器)。
当您控制实例化线程的代码时,您可以通过确保在应用程序停止时停止线程来解决问题。使用守护程序线程是一种很好的做法,但还不够,因为守护程序线程只在关闭Tomcat时自动死亡,而在取消部署应用程序时则不会自动死亡。
在更一般的情况下,当您不知道是谁创建了讨厌的帖子时,请检查source code和Finding Source of Thread Creation in a Java application。
<强>更新强>
完全不同的方法是使用非常有趣的Detect Who Created a Thread (w. Eclipse)。另请阅读该作者关于classloader泄漏的其他帖子。