Tomcat Guice / JDBC Speicherverlust
Erlebe ich einen Speicherverlust aufgrund von verwaisten threads in Tomcat. Besonders, es scheint, dass Guice und die JDBC-Treiber sind nicht das schließen von threads.
Aug 8, 2012 4:09:19 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [com.google.inject.internal.util.$Finalizer] but has failed to stop it. This is very likely to create a memory leak.
Aug 8, 2012 4:09:19 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
Ich weiß, das ist ähnlich wie bei anderen Fragen (wie diese eine), aber in meinem Fall die Antwort von "don' T worry about it" wird nicht ausreichend sein, da es verursacht Probleme für mich. Ich habe CI-server, die auch regelmäßig updates dieser Anwendung, und nach 6-10 lädt der CI-server hängen, da der Tomcat ist aus dem Speicher.
Ich muss in der Lage sein, um aufzuräumen, diese verwaisten threads, so kann ich mein CI-server mehr zuverlässig. Jede mögliche Hilfe würde geschätzt!
InformationsquelleAutor der Frage Jeff Allen | 2012-08-08
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich nur befasste sich mit diesem problem selber. Im Gegensatz zu einigen anderen Antworten, die ich nicht empfehlen Erteilung der
t.stop()
Befehl. Diese Methode ist veraltet, und das aus gutem Grund. Referenz Oracle ' s Gründendies zu tun.Aber es ist eine Lösung für die Beseitigung dieser Fehler ohne Rückgriff auf die
t.stop()
...Können Sie die meisten der code @Oso zur Verfügung gestellt, ersetzen Sie einfach den folgenden Abschnitt
Ersetzen Sie es mit der folgenden Methode zur Verfügung gestellt von der MySQL-Treiber:
Dieser sollte ordnungsgemäß Herunterfahren der thread, und der Fehler sollte Weg gehen.
InformationsquelleAutor der Antwort Bill
Ich habe das gleiche Problem, und, wie Jeff sagt, den "don' T worry about it" war nicht der Weg zu gehen.
Habe ich einen ServletContextListener, Stoppt das hing thread, wenn der Rahmen geschlossen wird, und dann registriert solche ContextListener auf die web.xml Datei.
Ich weiß schon, dass das anhalten eines Threads ist nicht ein eleganter Weg, um mit Ihnen umzugehen, aber ansonsten hält der server auf Absturz nach zwei oder drei setzt (es ist nicht immer möglich, starten Sie den app-server).
Die Klasse, die ich erstellt ist:
Nach dem erstellen der Klasse, dann registrieren Sie es auf dem web.xml Datei:
InformationsquelleAutor der Antwort
Ist die am wenigsten invasive Problemumgehung ist, zu zwingen, die Initialisierung des MySQL-JDBC-Treiber, die von code außerhalb des webapp-classloader.
In tomcat/conf/server.xml ändern Sie (in der Server-element):
zu
Dies setzt Voraus, Sie setzen die MySQL-JDBC-Treiber in tomcat-lib-Verzeichnis und nicht in Ihre webapp.Krieg WEB-INF/lib Verzeichnis, da der springende Punkt ist, um den Treiber zu laden vor und unabhängig von der webapp.
Referenzen:
http://bugs.mysql.com/bug.php?id=68556#c400606
http://tomcat.apache.org/tomcat-7.0-doc/config/listeners.html#JRE_Memory_Leak_Prevention_Listener_-_org.apache.catalina.core.JreMemoryLeakPreventionListener
http://markmail.org/message/dmvlkps7lbgpngil
InformationsquelleAutor der Antwort Stefan L
Ab MySQL connector 5.1.23 ab, eine Methode zu schließen, die aufgegeben-Verbindung cleanup-thread unten,
AbandonedConnectionCleanupThread.shutdown
.Jedoch, wir wollen keine direkten Abhängigkeiten im code auf die ansonsten undurchlässige JDBC-Treiber-code, also meine Lösung ist die Verwendung von Reflexion zu finden, die Klasse und Methode, und rufen Sie Sie, wenn gefunden. Die vollständige folgende code-snippet, das ist alles, was benötigt wird, durchgeführt im Rahmen der class loader laden der JDBC-Treiber:
Dieser sauber beendet den thread, wenn der JDBC-Treiber ist eine ausreichend aktuelle version von MySQL connector und sonst nichts.
Hinweis: es muss ausgeführt werden im Rahmen der class-loader, da der thread einen statischen Verweis, wenn der Fahrer der Klasse wird nicht oder hat nicht schon entladen ist, wenn dieser code ausgeführt wird, dann wird der thread nicht ausgeführt werden, für die spätere JDBC-Interaktionen.
InformationsquelleAutor der Antwort Lawrence Dol
Nahm ich die besten Teile der oben genannten Antworten zusammengefasst und in eine leicht erweiterbare Klasse. Diese kombiniert die Oso 's ursprünglichen Vorschlag mit Bill' s driver improvement und Software Monkey ' s Reflexion Verbesserung. (Ich mochte die Einfachheit von Stephan L s Antwort auch, aber manchmal ändern die Tomcat-Umgebung selbst ist nicht eine gute option, vor allem, wenn man mit autoskalierender oder die migration zu anderen web-container.)
Statt direkt Bezug auf den Namen der Klasse, die thread-Namen, und stop-Methode, die ich auch gekapselt in eine private inner class ThreadInfo. Mit Hilfe einer Liste dieser ThreadInfo Objekte, können Sie weitere lästige threads herunterzufahren, mit dem gleichen code. Dies ist eine etwas komplexere Lösung als die meisten Menschen wahrscheinlich brauchen, aber mehr arbeiten müssen in der Regel, wenn Sie das brauchen.
InformationsquelleAutor der Antwort Richard J. Barbalace
Ging ich einen Schritt weiter aus Oso,verbessert den code oben in zwei Punkten:
Fügte der Finalizer thread, um das need-to-kill-check:
Schlaf für eine Weile zu geben, die threads mal zu beenden. Ohne, dass tomcat gehalten, sich zu beschweren.
InformationsquelleAutor der Antwort BrunoJCM
Bill Lösung, sieht gut aus, allerdings habe ich eine andere Lösung gefunden direkt in der MySQL-bug-reports:
und die Antwort:
Ich hoffe, es hilft für alle, die noch kämpfen mit diesem Problem...
InformationsquelleAutor der Antwort wmiki
Sehen Um zu verhindern, dass ein Speicherverlust, der JDBC-Treiber wurde gewaltsam unregistrierte. Bill ' s Antwort deregisters alle Treiber-Instanzen sowie Instanzen, die gehören zu anderen web-Anwendungen. Ich habe erweiterte Bill ' s Antwort mit einem Häkchen, dass Sie die Treiber-Instanz gehört, auf der rechten
ClassLoader
.Hier ist der resultierende code (in einem separaten Verfahren, da meine
contextDestroyed
hat andere Dinge zu tun):Frage ich mich, ob der Aufruf
AbandonedConnectionCleanupThread.shutdown()
ist sicher. Kann es Störungen mit anderen web-Anwendungen? Ich hoffe nicht, denn dieAbandonedConnectionCleanupThread.run()
- Methode ist nicht statisch, sondern dieAbandonedConnectionCleanupThread.shutdown()
Methode ist.InformationsquelleAutor der Antwort Martijn Dirkse
Es scheint, dies wurde behoben in 5.1.41. Sie könnte ein upgrade Connector/J 5.1.41 oder neuer.
https://dev.mysql.com/doc/relnotes/connector-j/5.1/en/news-5-1-41.html
Wenn Sie einen Blick auf source-code, Sie nannten setDeamon(true) auf dem Gewinde, damit es nicht zu blockieren Herunterfahren.
InformationsquelleAutor der Antwort Le Zhang