SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-269] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-270] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-271] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-272] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-273] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-274] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-275] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-276] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-277] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-278] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-279] but has failed to stop it. This is very likely to create a memory leak.
May 26, 2015 4:12:52 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/scheduler] appears to have started a thread named [Timer-280] but has failed to stop it. This is very likely to create a memory leak.
这会导致Tomcat 服务器停止后Java进程尚未停止, 继续占用内存, 必须通过 类似 kill -9 之类的命令去杀死java进程.
这是由于在服务器停止时有些线程尚未销毁所引起的, 如ThreadLocal; Scheduler 启动的线程; JDBC driver等.
在stackoverflow 上有几篇 专门讨论这问题的帖子并提供了一些解决办法.
http://stackoverflow.com/questions/4899205/tomcat-6-memory-leaks-log-entries
http://stackoverflow.com/questions/11872316/tomcat-guice-jdbc-memory-leak
http://stackoverflow.com/questions/5292349/is-this-very-likely-to-create-a-memory-leak-in-tomcat
在吸取他们的解决办法的基础上, 作进一步的总结, 认为在web.xml中添加一个ServletContextListener在Context destroy的时候做一些事情是不错的, 具体代码如下:
public class ContextDestroyListener implements ServletContextListener {
private static Logger logger = LoggerFactory.getLogger(ContextDestroyListener.class);
public static final List<String> MANUAL_DESTROY_THREAD_IDENTIFIERS = Arrays.asList("QuartzScheduler", "scheduler_Worker");
@Override
public void contextInitialized(ServletContextEvent sce) {
//Ignore
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
destroyJDBCDrivers();
destroySpecifyThreads();
}
private void destroySpecifyThreads() {
final Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (needManualDestroy(thread)) {
synchronized (this) {
try {
thread.stop();
logger.debug(String.format("Destroy %s successful", thread));
} catch (Exception e) {
logger.warn(String.format("Destroy %s error", thread), e);
}
}
}
}
}
private boolean needManualDestroy(Thread thread) {
final String threadName = thread.getName();
for (String manualDestroyThreadIdentifier : MANUAL_DESTROY_THREAD_IDENTIFIERS) {
if (threadName.contains(manualDestroyThreadIdentifier)) {
return true;
}
}
return false;
}
private void destroyJDBCDrivers() {
final Enumeration<Driver> drivers = DriverManager.getDrivers();
Driver driver;
while (drivers.hasMoreElements()) {
driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
logger.debug(String.format("Deregister JDBC driver %s successful", driver));
} catch (SQLException e) {
logger.warn(String.format("Deregister JDBC driver %s error", driver), e);
}
}
}
}
来源于:http://blog.youkuaiyun.com/monkeyking1987/article/details/9182201