© DrHitch/Shutterstock.com
Memory Leaks Tools

1 Effective Java: Tool Time - Werkzeuge für die dynamische Memory-Leak-Analyse


Was ein Memory Leak in Java ist und unter welchen Umständen solche Leaks auftreten, wurde im shortcut zum Thema Memory Leaks geklärt. Mit welchen Strategien und Werkzeugen man nach einem vermuteten Memory Leak suchen kann, zeigt dieser thematisch weiterführende shortcut.

Zur Erinnerung: Es gibt unterschiedliche Arten von Memory Leaks. Alle gehen letztlich auf eine „unwanted reference“ zurück, also eine Referenz auf ein Objekt, das von der Programmlogik her nicht mehr gebraucht wird. Wegen der Referenz wird das fragliche Objekt vom Garbage Collector als erreichbar und benutzt erkannt, und sein Speicher kann deshalb nicht freigegeben werden.

Störend sind diese unerwünschten Referenzen, wenn sie größere Mengen an Speicher für eine längere Zeit am Leben erhalten. Das kann im schlimmsten Fall zu einem OutOfMemoryError der JVM und damit zum Programmabbruch führen. Oft ist ein solcher OutOfMemoryError der Ausgangspunkt für eine Memory-Leak-Analyse. Allerdings ist es dann schon reichlich spät, und es kann nur noch eine Post-mortem-Analyse gemacht werden. Dafür steht in der Regel wenig Information zur Verfügung. Oft ist es nicht mehr als ein Heap Dump.

Man muss aber nicht notwendigerweise warten, bis eine Anwendung wegen Speichermangels abbricht, ehe man nach Memory Leaks Ausschau hält. Man kann auch schon vorher – während die Applikation noch läuft – überprüfen, ob es Memory Leaks gibt. Das ist sogar empfehlenswert, denn während des Ablaufs der Anwendung können dynamische Daten von der JVM geholt werden, die weit mehr Informationen für die Analyse liefern, als es ein Heap Dump tun kann. Wir wollen uns im Folgenden beide Arten der Analyse ansehen:

  • die proaktive, dynamische Analyse am „lebenden Objekt“, d. h. während die Anwendung läuft
  • die reaktive Post-mortem-Analyse, nachdem die Anwendung bereits (wegen Speichermangels) abgebrochen ist

Dazu wollen wir das Beispiel aus dem vorangegangenen shortcut wieder aufgreifen [1]. Dort hatten wir ein kurzes, aber fehlerhaftes Programm mit Memory Leak gezeigt. Es ging um die Implementierung eines rudimentären Servers auf Basis der mit Java 7 eingeführten AsynchronousSocketChannels. Wir hatten pro Client einen Eintrag in einer Map gemacht, den wir aber am Ende der Client-Session nicht wieder gelöscht haben. Infolgedessen wächst die Map stetig an. Dies führt bei unserem Server zunächst zu Speicherengpässen mit auffallend langen Stop-the-World-Pausen des Garbage Collectors und am Ende zum Absturz mit OutOfMemoryError. Wie findet man jetzt ein solches Memory Leak?

Dynamische Memory-Leak-Analyse mit einem Profiler

Wir wollen es gar nicht so weit kommen lassen, dass der Server mit OutOfMemoryError abstürzt, sondern wir überlegen uns vorher, welche Daten wie lange leben sollen, und überprüfen dies. Die zugrunde liegende Überlegung ist, dass nahezu jede Anwendung speicherneutrale Use Cases hat. Während des Use Cases werden Daten gebraucht, die danach nicht mehr referenziert und damit freigegeben sein sollten. Wenn sie nicht freigegeben sind, haben wir ein Memory Leak, und zwar eines, das mit jeder Wiederholung des Use Cases stetig wächst. Solche speicherneutralen Use Cases können ganz unterschiedlicher Natur sein. In unserer Serveranwendung sind es ganz offensichtlich die einzelnen Client-Sessions.

Die Strategie für die dynamische Memory-Leak-Analyse ist eigentlich ganz einfach: Man identifiziert Anfang und Ende des speicherneutralen Use Cases. Dann verwendet man einen Memory Profiler, den man mit der JVM verbindet, in der die Anwendung läuft. Am Anfang und am Ende des Use Cases wird ein Memory Snapshot gemacht, und danach werden beide Snapshots verglichen. Wenn Objekte hinzugekommen sind, die den Use Case nicht hätten überleben dürfen, liegt offenbar ein Memory Leak vor.

Es sind noch ein paar Details zu beachten: Man muss erst die Garbage Collection auslösen, ehe ein Snapshot gezogen wird. Das liegt daran, dass unerreichbare Objekte nicht sofort vom Garbage Collector entfernt werden, wenn sie unerreichbar werden. Die Speicherfreigabe passiert erst mit einiger Verzögerung, nämlich dann, wenn die JVM beschließt, dass nun Zeit für eine Garbage Collection sei. Damit in den Snapshots nur noch die tatsächli...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang