ThreadLocal Memory Leak

Keine Kommentare

Da ich schon häufiger auf Memory Leaks gestoßen bin, die durch ThreadLocal Variablen auftreten, möchte ich dieses Phänomen genauer beleuchten.

ThreadLocal Variablen werden in Java benutzt, um Variablen an einen Thread zu binden – jeder Thread bekommt eine eigene, unabhängige Instanz dieser Variable zugewiesen. Normalerweise werden diese Variablen genutzt, um Status Informationen innerhalb eines Threads zu halten – z.B. die Benutzerkennung oder einen Mandanten.

Der Lebenszyklus einer ThreadLocal Instanz ist eng gekoppelt an den Lebenszyklus des entsprechenden Threads. Wird der Thread beendet und durch den GarbageCollector entfernt, sind auch die damit assoziierten ThreadLocal Variablen Kandidaten für den GarbageCollector.

Die Memory Probleme treten dann auf, wenn ThreadLocal Variablen innerhalb eines Application Servers verwendet werden. Application Server verwalten Thread in eigenen Thread Pools, um Ressourcen einzusparen und die Performance zu optimieren (Beispiel der Einstellungen für Tomcat 6 Http Conncector). Wird z.B. ein HttpServletRequest an die ServletEngine des Application Servers gesendet, wird für die Abarbeitung des Servlets ein freier, so genannten Worker-Thread aus dem entsprechenden Servlet ThreadPool entnommen. Dieser Thread arbeitet dann die Programmlogik des Servlets ab. Wird im Servlet oder der aus dem Servlet aufgerufenen Java Klassen eine ThreadLocal Variable genutzt, werden diese mit dem aktuellen Thread assoziiert. Nachdem das Servlet vom Thread abgearbeitet und die Response geschrieben wurde, wird der Thread aber nicht beendet und vom Garbage Collector aufgeräumt, sondern wieder in den ThreadPool zurückgegeben, so dass mit dem selben Thread einen neue Anfrage abgearbeitet werden kann. Die ThreadLocal Variablen bleiben also erhalten.

Je nach Größe des ThreadPools (in produktiven Systemen können das mehrere Hundert Threads sein) und der Größe der Objekte in der ThreadLocal Variable, kann das zu Problemen führen. Sind beispielsweise 200 Threads im ThreadPool aktiv und die ThreadLocal Varibale ist 5MB groß, belegen diese Variablen im schlimmsten Fall bereits 1GB Heap Speicher. Dies führt schnell zu erhöhter GC Aktivität und je nach Heap Größe zu einem Abbruch der JVM.

In einem konkreten Fall musste ein Server täglich neu gestartet werden, weil es zu einem OutOfMemoryError gekommen ist. Um das Prolem zu analysieren wurde zur Laufzeit ein Heapdump erzeugt. (siehe dazu den Blog Eintrag zur Erzeugung von Heapdumps) Die Analyse des Dumps mit Eclipse MAT hat ziemlich schnell gezeigt, dass es sich um ein ThreadLocal Problem handelt.

Der obige Screenshot zeigt den Dominator Tree des Dumps. Markiert sind 6 Threads die jeweils ca. 14MB Speicher referenzieren.

Der nächste Screenshot zeigt die Details eines Threads. Der hohe Speicherverbrauch ist auf eine ThreadLocal Variable zurückzuführen, die eine DOMParser inkl. geparstem Dokument referenziert – insgesamt mehr als 14MB groß. Da MAT auch die Inhalte der Objekte anzeigt, konnte an Hand des XML Inhalts identifiziert werden, dass die Dokumente zu einem WebService Aufruf gehören. Die Zugriffsklassen wurden mit JBoss WS generiert. Eine Suche in Google führte schnell zu einem Bug in der eingesetzten jbossws Version 1.2.0, der in der Version 1.2.1 gefixt wurde: „DOMUtils doesn’t clear thread locals“.

Das Beispiel zeigt, dass man vorsichtig sein muss, wenn man ThreadLocal Variablen innerhalb eines ApplicationServer verwendet (vor allem wenn man Application Server Hersteller ist). Es ist wichtig dafür zu sorgen, dass der Inhalt der Variablen gelöscht wird, bevor der Thread wieder in den ThreadPool zurückgestellt wird. Die Daten sind auch fachlich gefährlich, wenn Sie nicht gelöscht werden, da nicht vorhergesagt werden kann, welche Anfrage der Thread als nächstes bearbeitet.

In einigen Projekten in denen wir ThreadLocal Variablen nutzen, haben wir einen ServletFilter geschrieben, der dafür sorgt, dass die Daten bereinigt werden.

Als Mitbegründer und Advisor der codecentric AG berät Mirko bei der strategischen Ausrichtung des Unternehmens. Er ist Geschäftsführer und Mitgründer der Startups CenterDevice und Instana – beides disruptive Geschäftsmodelle auf Basis von Big-Data- und Cloud-Technologien.

Seine Interessen liegen im Bereich der Veränderung von Geschäftsmodellen durch moderne Technologien und Software, also der zunehmenden Digitalisierung der Welt und den daraus resultierenden Veränderungen und Potential für Unternehmen.
Im Privatleben widmet er sich am liebsten seiner Familie, zum sportlichen Ausgleich fährt er Mountainbike.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.