2012-03-29 55 views
5

我的Tomcat 7時的Java web應用程序的內存泄漏報道稱,有可能是內存泄漏在我的webapp使用ScheduledExecutorService的

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一個長期運行的任務時,web應用程序啓動是被初始化。

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上,我發現它一旦啓動,它運行良好大約兩天,然後任務似乎沒有運行。日誌中也沒有例外或錯誤。

我在這裏做錯了什麼嗎?是否真的存在內存泄漏?

回答

6

調用fScheduler.shutdownNow();是不夠的:

有沒有保證盡最大努力,試圖積極停止處理執行任務。

JavaDoc

相反,你必須明確地等待當前正在運行的任務:

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

嗯..我想這可能是在極少數情況下,我的任務運行每240分鐘,不應該超過幾分鐘才能完成。如果在第300分鐘,我儘量關機,當我的任務沒有運行,不應該能正常關機嗎?你的回答很可能是正確的,但我只是好奇:) – Krishnaraj 2012-03-29 18:13:54

+0

@Krishnaraj你確定你的任務正如你認爲的那樣儘快結束嗎?您可能需要記錄任務開始/停止的時間,以確認其未被阻止。 – 2012-03-29 18:47:06

+0

@ increment1是的,我的任務在不超過5分鐘內完成。 – Krishnaraj 2012-03-31 05:11:21

1

我認爲你不應該調用來自監聽器,而是直接從servlet關機。

contextDestroyed()對於執行器服務來說已經太晚了。如javadoc 中所述,所有servlet和過濾器都將被銷燬之前任何ServletContextListeners都會收到關於上下文銷燬的通知。

而重寫的servlet destroy()應作爲根據的Javadoc 這種方法確定給servlet的一個機會,清理正在舉行的任何資源(例如,內存,文件句柄,線程 .. 。

@Override 
public void destroy() { 


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

    super.destroy(); 
} 
+0

使用Servlet。destroy()是一個非常糟糕的主意。只要它喜歡,容器可以從內存中自由地卸載Servlet(在進程中調用destroy())。 – 2012-05-02 12:49:38

+0

@MarkThomas同樣來自'Servlet' Javadoc *在servlet容器調用這個方法之後,它不會再在這個servlet上調用服務方法。*。換句話說,servlet將永遠不會再被使用。我看不出你的問題是什麼。當調用destroy()時,如果你將一個資源綁定到這個servlet(線程,文件句柄,...),那麼這個servlet就會被徹底銷燬,並且任何捆綁的資源也應該被銷燬。 – 2012-05-11 07:15:10

+0

您需要閱讀Servlet規範,尤其是servlet生命週期的規範。 init()方法在創建實例時被調用一次(創建一個實例以處理所有請求)。 service()方法每個請求被調用一次。同一個實例可以處理多個併發請求。 destroy()方法在實例卸載時被調用,該實例可以在任何時間點(如果在實例被銷燬後接收到另一個servlet請求,則將創建新的實例)。這一切都忽略了depreacted單線程模型。 – 2012-05-11 07:43:32

相關問題