使用ScheduledExecutorService时,Java webapp内存泄漏

我的Tomcat 7报告我的webapp可能存在内存泄漏

SEVERE: The web application [/mywebapp] appears to have started a thread named [pool-1-thread-1] but has failed to stop it. This is very likely to create a memory leak. 

我的webapp中有一个长时间运行的任务,当webapp启动时会被初始化。

 public class MyContextListener implements ServletContextListener{ Scheduler scheduler = null; public MyContextListener(){ scheduler = new Scheduler(); } @Override public void contextDestroyed(ServletContextEvent arg0) { scheduler.stop(); } @Override public void contextInitialized(ServletContextEvent arg0) { scheduler.start(); } } 

..和我的Scheduler.java

 public class Scheduler { private final ScheduledExecutorService fScheduler; public Scheduler() { fScheduler = Executors.newScheduledThreadPool(1); } public void start(){ fScheduler.scheduleWithFixedDelay(new Runnable() { @Override public void run() { //Perform some task } }, 1, 240, TimeUnit.MINUTES); } public void stop(){ fScheduler.shutdownNow(); } 

}

即使我调用scheduler.stop(); 当关闭服务器时,它仍然报告可能存在内存泄漏。

这个应用程序部署在jelastic.com上,我发现它一旦启动,它运行良好大约两天,然后任务似乎没有运行。 日志中也没有例外或错误。

我在这做错了吗? 真的存在潜在的内存泄漏吗?

调用fScheduler.shutdownNow(); 是不足够的:

除了尽力尝试停止处理主动执行任务之外,没有任何保证。

来自JavaDoc 。

相反,您必须明确等待当前正在运行的任务:

 fScheduler.shutdownNow(); fScheduler.awaitTermination(10, TimeUnit.SECONDS); 

我相信你不应该从Listener调用shutdown,而是直接从Servlet调用。

对于执行程序服务,listener的contextDestroyed()为时已晚。 正如javadoc中所述,在向任何ServletContextListener通知上下文破坏 之前, 所有servlet和filter都将被 销毁。

根据javadoc重写servlet destroy()应该没问题。 这个方法为servlet提供了清理所有资源的机会(例如,内存,文件句柄, 线程

 @Override public void destroy( ) { fScheduler.shutdownNow(); fScheduler.awaitTermination(10, TimeUnit.SECONDS); super.destroy( ); }