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.csdn.net/monkeyking1987/article/details/9182201