Speicherverbrauch analysieren

Beim Test von JAVA-Anwendungen ist es eine „good practice", den Speicherverbrauch der JVM zu beobachten, um die Größe des zu allokierenden Speichers (JVM-Optionen -Xms und -Xmx) zu ermitteln und Memory Leaks auszuschließen.

Trau dem Task-Manager nicht ...

Die Versuchung liegt nahe, dabei zunächst auf Betriebssystem-Tools (wie den Windows Task-Manager) zurückzugreifen. Aber Achtung: die dort gemeldete Speicherauslastung entspricht mitnichten dem tatsächlichen Speicherverbrauch der JVM, denn:

  • Im Task-Manager wird der Speicherverbrauch des JAVA-Prozesses angezeigt und nicht der JAVA Heap Size, der eigentlich interessiert, weil dies der durch die Anwendung verbrauchte Speicher ist. Neben dem JAVA Heap Size benötigt der Prozess weiteren Speicher für die JVM und deren Datenstrukturen.
  • Im Task-Manager wird häufig nicht der von der JVM tatsächlich verwendete Speicher dargestellt. Gibt die JVM in Zuge ihrer Garbage Collection Speicher frei, so wird dies von der JVM nicht zwangsläufig an das Betriebssystem propagiert. Im Task-Manager wird also ein viel höherer Wert angezeigt als der JAVA Heap tatsächlich einnimmt. Folge: Als Beobachter hat man den Eindruck, als ob die JAVA-Anwendung ständig „am Anschlag" arbeitet, obwohl der Anwendung noch massig Speicher zur Verfügung steht.

... sondern lieber den JAVA-Bordmitteln

Deshalb kann ein zuverlässiges Speicher-Monitoring nur mit Werkzeugen erfolgen, die exakte Werte für den JAVA Heap Size bzw. dessen einzelne Speicherbereiche (Eden Space, Survivor Space...) liefern. Ein ideales Tool ist die JConsole, die seit JAVA 5 zum Lieferumfang des JDK gehört (zu finden im Verzeichnis JDK_HOME/bin).

Musste unter JAVA 5 die Verwendung der JConsole beim Starten der Anwendung über die Kommandozeile mit dem Parameter -Dcom.sun.management.jmxremote noch explizit ermöglicht werden (Starten des JMX Agent), ist seit JAVA 6 ein unmittelbares Verbinden der JConsole auf den JAVA-Prozess möglich. Hierzu wird jconsole.exe aufgerufen und auf eine lokale oder eine Remote-Anwendung verbunden.

Neben der Auslastung der einzelnen Speicherbereiche (Heap und Non-Heap) lassen sich über die JConsole weitere Kenngrößen verfolgen (z.B. Threads). Sägezahnförmige Verläufe der Speicherauslastungen lassen erkennen, dass bei der Garbage Collection jeweils wieder ausreichend Speicher freigegeben wird und z.B. kein Memory Leak in der Applikation vorliegt. Auch eine Detailanalyse der einzelnen Memory Pools und deren Tuning über JVM Optionen wird damit möglich.

Alternativ kann zur Analyse auch VisualVM eingesetzt werden. VisualVM wird seit JAVA 6 Update 7 als Bestandteil des JDK mit ausgeliefert - es vereint einige der bisherigen JDK-eigenen Werkzeuge unter einer modernen, Netbeans-basierten Oberfläche. Die analysierten Anwendungen können dabei auch in älteren Umgebungen laufen - die zur Überwachung des Speicherverbrauchs erforderliche Monitoring-Funktionalität wird beispielsweise bereits ab JAVA 1.4.2 unterstützt. Der volle Funktionsumfang ist jedoch erst gegeben, wenn die Anwendung in einer JAVA 6-Umgebung abläuft.

Referenzen
http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html
https://visualvm.java.net/