2012-03-29 18 views
5

My Tomcat 7 donosi, że może być przeciek pamięci w moim webappJava webapp wyciek pamięci podczas korzystania 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. 

Mam długie zadanie działa w moim webapp, który pobiera zainicjowany gdy webapp jest uruchomiona.

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(); 
} 

} 

.. i moja 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(); 
} 

}

Chociaż nazywając scheduler.stop(); podczas zamykania serwera, jego wciąż zgłoszenie nie może być wyciek pamięci.

Ta aplikacja jest wdrożona na stronie jelastic.com i stwierdzam, że po uruchomieniu działa dobrze przez około dwa dni, a następnie zadania nie wydają się działać. Nie ma wyjątków ani błędów w dziennikach.

Czy robię coś złego tutaj? Czy naprawdę istnieje potencjalny wyciek pamięci?

Odpowiedz

6

Wywołanie fScheduler.shutdownNow(); nie wystarczy:

Nie ma żadnych gwarancji poza best-effort próbuje aktywnie zatrzymać przetwarzanie wykonywania zadań.

Od JavaDoc.

Zamiast tego należy jawnie czekać do zadań, które są aktualnie uruchomione:

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

hmm .. Myślałem, że może być w rzadkich przypadkach. moim zadaniem kursuje co 240 minut i nie powinno trwać dłużej niż kilka minut, aby zakończyć. Jeśli w 300. min próbie wyłączenia, kiedy moje zadanie nie działa, czy nie powinien być w stanie poprawnie zamknąć? Odpowiedź jest najprawdopodobniej słuszna, ale jestem po prostu ciekawa :) – Krishnaraj

+0

@Krishnaraj Czy jesteś pewien, że twoje zadanie kończy się tak szybko, jak myślisz, że powinno? Możesz chcieć zalogować się, kiedy twoje zadanie się uruchamia/zatrzymuje, aby sprawdzić, czy nie jest blokowane. –

+0

@ increment1 Tak, moje zadania kończą się w nie więcej niż 5 minutach. – Krishnaraj

1

Uważam, że nie powinno wywołać zamknięcie od słuchacza, ale z Servlet bezpośrednio.

contextDestroyed() słuchacza jest za późno na usługę executora. Jak podano w javadoc Wszystkie serwlety i filtry zostaną zniszczoneprzedwszelkie obiekty ServletContextListeners są powiadamiane o zniszczeniu kontekstu.

natomiast nadrzędne serwlet destroy() powinno być OK, ponieważ zgodnie z javadoc Metoda ta daje serwlet możliwość oczyścić wszelkie środki, które odbywają się (na przykład, pamięć, uchwytów plików,nici .. .

@Override 
public void destroy() { 


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

    super.destroy(); 
} 
+0

Korzystanie z serwletu.destroy() to bardzo zły pomysł. Kontener może zwolnić serwlet z pamięci (wywołując metodę destroy) w dowolnym momencie. –

+0

@MarkThomas Również z Javadoc 'Servlet' * Po tym, jak kontener serwletu wywoła tę metodę, nie wywoła ponownie metody usługi w tym serwlecie. *. Innymi słowy, serwlet nigdy nie zostanie użyty ponownie. Nie widzę twojego problemu. Jeśli powiązamy zasób z tym serwletem (wątek, uchwyty plików, ...), gdy wywoływane jest 'destroy()', serwlet jest właśnie taki, ostatecznie zniszczony, a każdy powiązany zasób również powinien zostać zniszczony. –

+0

Należy przeczytać specyfikację serwletu, w szczególności sesję dotyczącą cyklu życia serwletu. Metoda init() jest wywoływana raz, gdy instancja jest tworzona (jedna instancja jest tworzona w celu obsługi wszystkich żądań). Metoda service() zostaje wywołana raz na żądanie. To samo wystąpienie może obsługiwać wiele jednoczesnych żądań. Metoda destroy() jest wywoływana, gdy instancja jest rozładowywana, co może nastąpić w dowolnym momencie (jeśli zostanie odebrane inne żądanie dla serwletu po zniszczeniu instancji, zostanie utworzona nowa instancja). To wszystko ignoruje zdezagresowany model z pojedynczym gwintem. –