4

我仍然在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

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

4

2 回答 2

3

这可能没什么大不了的(只需杀死 -9 或其他东西)并且很容易修复。只需弄清楚哪个 webapp 在 /LoggingMonitor 的上下文中运行,然后 grep 它的代码库...

new Timer();

...并将它们全部替换为...

new Timer( true );

java.util.Timer 默认不在守护线程中运行。您需要 webapps 中的任何 Timer 在守护线程上运行(否则容器无法正常关闭,因为它正在等待 Timer 线程结束,而它永远不会这样做)。找到所有“new 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 太容易了,守护进程或其他方式。

于 2011-12-30T09:25:19.740 回答
2

如果您在取消部署/重新部署应用程序时总是停止 Tomcat,那么该消息并不是什么大问题,否则这些操作会导致内存泄漏,这一个大问题,特别是在生产中。

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

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

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

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

更新

一种完全不同的方法是使用非常有趣的Leak Prevention Listener。另请阅读该作者关于类加载器泄漏的其他帖子。

于 2014-04-28T08:27:42.187 回答