是否知道如何处理以下Tomcat日志条目:
SEVERE: The web application [/my-app] appears to have started a thread named [Thread-11] but has failed to stop it. This is very likely to create a memory leak.
Jun 29, 2015 11:14:33 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads我要在关闭tomcat 7.0.42的时候得到它们。
线程转储如下所示:
"Thread-11" daemon prio=10 tid=0x00007fedc0bd5000 nid=0x2983 waiting on condition [0x00007fedbacef000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.my.app.Test$WorkerThread.run(Test.java:248)其中java行248为:睡眠(1000*60*pollIntervalMinutes);
public void start()
{
WorkerThread t= new WorkerThread(this);
t.setDaemon(true);
t.start();
}
private class WorkerThread extends Thread
{
Controller controller=null;
int pollIntervalMinutes=0;
private boolean alive = true;
public WorkerThread(Controller controller)
{
this.controller=controller;
pollIntervalMinutes=60;
}
@Override
public void run()
{
while(alive)
{
try
{
sleep(1000*60*pollIntervalMinutes);
controller.createAllProjectsIfNeeded();
}
catch (Exception e)
{
alive = false;
}
}
}
}谢谢
发布于 2015-06-29 17:47:53
问题似乎是Tomcat没有做任何尝试来阻止应用程序创建的非托管线程。
查找报告错误的org.apache.catalina.loader.WebappClassLoader clearReferencesThreads的实现,JVM线程将从清理过程中跳过。
因此,我要说的是,InterruptedException从未抛出,因此也不会像预期的那样,将活动设置为false。
@SuppressWarnings("deprecation")
private void clearReferencesThreads() {
Thread[] threads = getThreads();
// Iterate over the set of threads
for (Thread thread : threads) {
if (thread != null) {
ClassLoader ccl = thread.getContextClassLoader();
if (ccl == this) {
// Don't warn about this thread
if (thread == Thread.currentThread()) {
continue;
}
// JVM controlled threads
ThreadGroup tg = thread.getThreadGroup();
if (tg != null &&
JVM_THREAD_GROUP_NAMES.contains(tg.getName())) {
// HttpClient keep-alive threads
if (clearReferencesHttpClientKeepAliveThread &&
thread.getName().equals("Keep-Alive-Timer")) {
thread.setContextClassLoader(parent);
log.debug(sm.getString(
"webappClassLoader.checkThreadsHttpClient"));
}
// Don't warn about remaining JVM controlled threads
continue;
}
// Skip threads that have already died
if (!thread.isAlive()) {
continue;
}
// TimerThread can be stopped safely so treat separately
if (thread.getClass().getName().equals(
"java.util.TimerThread") &&
clearReferencesStopTimerThreads) {
clearReferencesStopTimerThread(thread);
continue;
}
if (isRequestThread(thread)) {
log.error(sm.getString("webappClassLoader.warnRequestThread",
contextName, thread.getName()));
} else {
log.error(sm.getString("webappClassLoader.warnThread",
contextName, thread.getName()));
}
// Don't try an stop the threads unless explicitly
// configured to do so
if (!clearReferencesStopThreads) {
continue;
}
// If the thread has been started via an executor, try
// shutting down the executor
try {
Field targetField =
thread.getClass().getDeclaredField("target");
targetField.setAccessible(true);
Object target = targetField.get(thread);
if (target != null &&
target.getClass().getCanonicalName().equals(
"java.util.concurrent.ThreadPoolExecutor.Worker")) {
Field executorField =
target.getClass().getDeclaredField("this$0");
executorField.setAccessible(true);
Object executor = executorField.get(target);
if (executor instanceof ThreadPoolExecutor) {
((ThreadPoolExecutor) executor).shutdownNow();
}
}
} catch (SecurityException e) {
log.warn(sm.getString(
"webappClassLoader.stopThreadFail",
thread.getName(), contextName), e);
} catch (NoSuchFieldException e) {
log.warn(sm.getString(
"webappClassLoader.stopThreadFail",
thread.getName(), contextName), e);
} catch (IllegalArgumentException e) {
log.warn(sm.getString(
"webappClassLoader.stopThreadFail",
thread.getName(), contextName), e);
} catch (IllegalAccessException e) {
log.warn(sm.getString(
"webappClassLoader.stopThreadFail",
thread.getName(), contextName), e);
}
// This method is deprecated and for good reason. This is
// very risky code but is the only option at this point.
// A *very* good reason for apps to do this clean-up
// themselves.
thread.stop();
}
}
}
}我可以想出三种方法来避免内存泄漏:
如何添加关机挂钩
ExecutorService中,并在应用程序关闭事件时调用shutdownNow()。
这可以通过使用@WebListener注释的服务类来实现,并在方法:contextDestroyed(ServletContextEvent event)中调用shutdownNow()。shutdownNow()
尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。此方法不等待主动执行任务终止。使用
awaitTermination来完成这个任务。 除了尽力停止处理积极执行的任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。
发布于 2015-06-29 20:06:41
我建议您在上下文中添加一个ServletContextListener (示例),它与线程通信,并在上下文被破坏时停止它。这样,当您的应用程序卸载(如果您删除或替换它),线程停止,并启动一个新的。
https://stackoverflow.com/questions/31121241
复制相似问题