使用ScheduledExecutorService时,Java webapp内存泄漏

时间:2012-03-29 17:56:32

标签: java tomcat memory-leaks

我的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上,我发现它一旦启动,它运行良好大约两天,然后任务似乎没有运行。日志中也没有例外或错误。

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

2 个答案:

答案 0 :(得分:6)

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

  

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

来自JavaDoc

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

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

答案 1 :(得分:1)

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

监听器的

contextDestroyed()对于执行程序服务来说太迟了。正如javadoc 中所述,所有servlet和过滤器都将被销毁 之前,任何ServletContextListeners都会被告知上下文破坏。

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

@Override
public void destroy(  ) {


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

     super.destroy(  );
}