2012-03-29 12 views
5

Mein Tomcat 7 verwendet, wird berichtet, dass es in meinem Webapp, die initialisiert wird, wenn die Webapp gestartetJava Webapp Speicherleck, wenn 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. 

Ich habe eine lange laufende Aufgabe ein Speicherleck in meinem Webapp sein kann.

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

} 

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

}

Auch wenn ich scheduler.stop(); Aufruf, wenn Sie den Server herunterzufahren, seine immer noch da Berichterstattung ein Speicherverlust sein könnte.

Diese App ist auf jelastic.com im Einsatz und ich finde, dass es nach dem Start gut läuft für etwa zwei Tage und dann scheinen die Aufgaben nicht ausgeführt werden. Es gibt keine Ausnahmen oder Fehler in den Protokollen.

Mache ich hier etwas falsch? Gibt es wirklich ein mögliches Speicherleck?

Antwort

6

fScheduler.shutdownNow(); Aufruf ist nicht genug:

Es gibt keine Garantien über Best-Effort versucht Verarbeitung aktiv zu stoppen Aufgaben ausführt.

Von JavaDoc.

Stattdessen müssen Sie explizit für die Aufgaben warten, die derzeit ausgeführt werden:

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

hmm .. ich dachte, es in seltenen Fällen sein kann. Meine Aufgabe alle 240 Minuten läuft und sollte nicht länger als ein paar Minuten zu beenden. Wenn bei der 300. min versuche ich zum Herunterfahren, wenn meine Aufgabe läuft nicht, sollte es nicht in der Lage sein, ordnungsgemäß herunterzufahren? Ihre Antwort ist höchstwahrscheinlich richtig, aber ich bin nur neugierig :) – Krishnaraj

+0

@Krishnaraj Sind Sie sicher, dass Ihre Aufgabe so schnell beendet wird, wie Sie es für richtig halten? Sie möchten möglicherweise protokollieren, wenn Ihre Aufgabe gestartet/gestoppt wird, um zu überprüfen, ob sie blockiert wird. –

+0

@ increment1 Ja, meine Aufgaben sind in nicht mehr als 5 Minuten abgeschlossen. – Krishnaraj

1

Ich glaube, Sie nicht das Herunterfahren von den Zuhörern anrufen sollten, sondern aus dem Servlet direkt.

contextDestroyed() des Zuhörers ist zu spät für den Executor-Service. Wie im javadoc angegeben, werden alle Servlets und Filter zerstörtvoralle ServletContextListeners werden von Kontext Zerstörung benachrichtigt.

während das Überschreiben der Servlet destroy() wie nach dem javadoc Diese Methode OK sein sollte, gibt dem Servlet die Möglichkeit, alle Ressourcen zu bereinigen, die (beispielsweise festgehalten werden, Speicher, Datei-Handles,Fäden ..

.
@Override 
public void destroy() { 


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

    super.destroy(); 
} 
+0

Verwenden von Servlet.destroy() ist eine sehr schlechte Idee. Dem Container steht es frei, ein Servlet aus dem Speicher zu entladen (dabei wird destroy() aufgerufen), wann immer es will. –

+0

@MarkThomas Auch ex 'Servlet' Javadoc * Nachdem der Servlet-Container diese Methode aufgerufen hat, wird er die Servicemethode für dieses Servlet nicht erneut aufrufen. *. Mit anderen Worten, das Servlet wird nie wieder verwendet. Ich kann nicht sehen, was dein Problem ist. Wenn Sie eine Ressource an dieses Servlet binden (Thread, Datei-Handles, ...), wenn 'destroy()' aufgerufen wird, ist das Servlet genau das, definitiv zerstört, und jegliche gebundene Ressource sollte ebenfalls zerstört werden. –

+0

Sie müssen die Servlet-Spezifikation lesen, insbesondere den Servlet-Lebenszyklus. Die init() -Methode wird einmal aufgerufen, wenn die Instanz erstellt wird (eine Instanz wird erstellt, um alle Anfragen zu bearbeiten). Die Methode service() wird einmal pro Anfrage aufgerufen. Dieselbe Instanz kann mehrere gleichzeitige Anforderungen verarbeiten. Die destroy() -Methode wird aufgerufen, wenn die Instanz entladen wird, was zu jedem Zeitpunkt möglich ist (wenn nach dem Löschen der Instanz eine weitere Anfrage für das Servlet eingeht, wird eine neue Instanz erstellt). Dies alles ignoriert das enttäuschte Single-Threaded-Modell. –

Verwandte Themen