Der Akt 4 unserer Serie über OutOfMemoryError schloss mit dem Ausblick auf bessere Verfahren zum Aufspüren von Memory Leaks. Wir haben beschrieben, dass man in HeapDumps zwar große Objekte finden kann, die Aussagekraft über Leaks aber oft nur dann hoch ist, wenn ein OutOfMemoryError aufgetreten ist. Um dann in einer post-mortem Analyse etwas finden zu können sollte unbedingt der Parameter -XX:+HeapDumpOnOutOfMemoryError verwendet werden.
Doch dieses Verfahren ist nicht immer gut geeignet um Memory Leaks zu finden. Zum einen muss man warten bis ein Fehler auftritt, zum anderen führt ein sehr langsam wachsendes Memory Leak vielleicht garnicht zu einem OutOfMemoryError, weil die Server, und damit die JVMs, sowieso regelmäßig für Deployments oder gerade zur Bekämpfung von Speicherproblemen neu gestartet werden.
Das Verfahren solche “schleichenden” Memory Leaks zu finden ist deutlich komplizierter und aufwändiger als eine post-mortem Analyse. Mittels mehrerer, zeitlich versetzten, Dumps ist es zwar möglich wachsende Strukturen über Zeit zur erkennen, in der Praxis ist dies aber häufig sehr mühselig und oft kaum informativer als einzelne Dumps, da die Vielzahl von normalen Schwankungen zwischen Dumps die wirklich interessanten Delta doch deutlich überlagert. Zudem muss man zur Analyse auch die das Memory Leak verursachenden Use Cases kennen, um das Problem gezielt nachstellen zu können. Ferner ist es in Produktion zudem fast unmöglich einen vollen Heapdump zu ziehen, da das System, je nach Heap Größe, mehrere Sekunden bis Minuten still steht.
Besser ist es zur Laufzeit des Programms den Heap und die darin enthaltenen relevanten Objekte dauerhaft zu überwachen. So kann herausgefunden werden welche Objektstrukturen über eine längere Zeit weiter wachsen. Und da das Programm ja noch läuft, kann ferner auch ermittelt werden welcher Code mit dieser Objektstruktur interagiert. Dies ist mit HeapDumps nicht möglich, da keinerlei Codeinformationen enthalten sind.
(weiterlesen …)