Verschiedene Möglichkeiten zum Erfassen von Java-Heap-Dumps

1. Einleitung

In diesem Artikel werden verschiedene Möglichkeiten zum Erfassen eines Heap-Dumps in Java gezeigt.

Ein Heap-Dump ist eine Momentaufnahme aller Objekte, die sich zu einem bestimmten Zeitpunkt in der JVM im Speicher befinden . Sie sind sehr nützlich, um Probleme mit Speicherverlusten zu beheben und die Speichernutzung in Java-Anwendungen zu optimieren.

Heap-Dumps werden normalerweise in hprof-Dateien im Binärformat gespeichert. Wir können diese Dateien mit Tools wie jhat oder JVisualVM öffnen und analysieren. Für Eclipse-Benutzer ist es außerdem sehr üblich, MAT zu verwenden.

In den nächsten Abschnitten werden wir mehrere Tools und Ansätze zum Generieren eines Heap-Dumps durchgehen und die Hauptunterschiede zwischen ihnen zeigen.

2. JDK-Tools

Das JDK enthält mehrere Tools zum Erfassen von Heap-Dumps auf unterschiedliche Weise. Alle diese Tools befinden sich im Ordner bin im JDK-Ausgangsverzeichnis . Daher können wir sie über die Befehlszeile starten, solange dieses Verzeichnis im Systempfad enthalten ist.

In den nächsten Abschnitten wird gezeigt, wie diese Tools zum Erfassen von Heap-Dumps verwendet werden.

2.1. jmap

jmap ist ein Tool zum Drucken von Statistiken über den Speicher in einer laufenden JVM. Wir können es für lokale oder entfernte Prozesse verwenden.

Um einen Heap-Dump mit jmap zu erfassen, müssen Sie die Dump- Option verwenden:

jmap -dump:[live],format=b,file= 

Zusammen mit dieser Option sollten wir mehrere Parameter angeben:

  • live : Wenn diese Option aktiviert ist, werden nur Objekte mit aktiven Referenzen gedruckt und diejenigen verworfen, die für die Müllabfuhr bereit sind. Dieser Parameter ist optional
  • format = b : Gibt an, dass die Dump-Datei im Binärformat vorliegt. Wenn nicht, ist das Ergebnis das gleiche
  • Datei : Die Datei, in die der Speicherauszug geschrieben wird
  • pid : id des Java-Prozesses

Ein Beispiel wäre wie folgt:

jmap -dump:live,format=b,file=/tmp/dump.hprof 12587

Denken Sie daran , dass wir leicht die bekommen kann pid eines Java - Prozess unter Verwendung des JPS - Befehl.

Beachten Sie, dass jmap im JDK als experimentelles Tool eingeführt wurde und nicht unterstützt wird. In einigen Fällen kann es daher vorzuziehen sein, stattdessen andere Tools zu verwenden.

2.2. jcmd

jcmd ist ein sehr vollständiges Tool, das Befehlsanforderungen an die JVM sendet. Wir müssen es auf demselben Computer verwenden, auf dem der Java-Prozess ausgeführt wird.

Einer der vielen Befehle ist der GC.heap_dump . Wir können es verwenden, um einen Heap-Dump zu erhalten, indem wir einfach die PID des Prozesses und den Pfad der Ausgabedatei angeben:

jcmd  GC.heap_dump 

Wir können es mit denselben Parametern ausführen, die wir zuvor verwendet haben:

jcmd 12587 GC.heap_dump /tmp/dump.hprof

Wie bei jmap liegt der generierte Speicherauszug im Binärformat vor.

2.3. JVisualVM

JVisualVM ist ein Tool mit einer grafischen Benutzeroberfläche, mit der wir Java-Anwendungen überwachen, Fehler beheben und Profile erstellen können . Die GUI ist einfach, aber sehr intuitiv und einfach zu bedienen.

Eine der vielen Optionen ermöglicht es uns, einen Heap-Dump zu erfassen. Wenn wir mit der rechten Maustaste auf einen Java-Prozess klicken und die Option "Heap Dump" auswählen , erstellt das Tool einen Heap Dump und öffnet ihn in einer neuen Registerkarte:

Beachten Sie, dass wir den Pfad der erstellten Datei im Abschnitt „Grundlegende Informationen“ finden .

Ab JDK 9 ist Visual VM nicht in den Distributionen Oracle JDK und Open JDK enthalten. Wenn wir Java 9 oder neuere Versionen verwenden, können wir die JVisualVM daher von der Open Source-Projektsite von Visual VM abrufen.

3. Erfassen Sie einen Heap Dump automatisch

Alle in den vorherigen Abschnitten gezeigten Tools dienen dazu, Heap-Dumps zu einem bestimmten Zeitpunkt manuell zu erfassen. In einigen Fällen möchten wir einen Heap-Dump erhalten, wenn ein java.lang.OutOfMemoryError auftritt, damit wir den Fehler untersuchen können.

In diesen Fällen stellt Java die Befehlszeilenoption HeapDumpOnOutOfMemoryError bereit , die einen Heap-Dump generiert, wenn ein java.lang.OutOfMemoryError ausgelöst wird:

java -XX:+HeapDumpOnOutOfMemoryError

Standardmäßig wird der Speicherauszug in einer Datei java_pid.hprof in dem Verzeichnis gespeichert, in dem die Anwendung ausgeführt wird. Wenn wir eine andere Datei oder ein anderes Verzeichnis angeben möchten, können wir dies in der Option HeapDumpPath festlegen :

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=

Wenn unsere Anwendung mit dieser Option keinen Speicher mehr hat, können wir in den Protokollen die erstellte Datei sehen, die den Heap-Dump enthält:

java.lang.OutOfMemoryError: Requested array size exceeds VM limit Dumping heap to java_pid12587.hprof ... Exception in thread "main" Heap dump file created [4744371 bytes in 0.029 secs] java.lang.OutOfMemoryError: Requested array size exceeds VM limit at com.baeldung.heapdump.App.main(App.java:7)

Im obigen Beispiel wurde es in die Datei java_pid12587.hprof geschrieben .

Wie wir sehen können, ist diese Option sehr nützlich und es entsteht kein Overhead, wenn eine Anwendung mit dieser Option ausgeführt wird. Daher wird dringend empfohlen, diese Option immer zu verwenden, insbesondere in der Produktion.

Schließlich kann diese Option auch zur Laufzeit mithilfe der HotSpotDiagnostic- MBean angegeben werden . Dazu können wir JConsole verwenden und die Option HeapDumpOnOutOfMemoryError VM auf true setzen :

Weitere Informationen zu MBeans und JMX finden Sie in diesem Artikel.

4. JMX

The last approach that we'll cover in this article is using JMX. We'll use the HotSpotDiagnostic MBean that we briefly introduced in the previous section. This MBean provides a dumpHeap method that accepts 2 parameters:

  • outputFile: the path of the file for the dump. The file should have the hprof extension
  • live: if set to true it dumps only the active objects in memory, as we've seen with jmap before

In the next sections, we'll show 2 different ways to invoke this method in order to capture a heap dump.

4.1. JConsole

The easiest way to use the HotSpotDiagnostic MBean is by using a JMX client such as JConsole.

If we open JConsole and connect to a running Java process, we can navigate to the MBeans tab and find the HotSpotDiagnostic under com.sun.management. In operations, we can find the dumpHeap method that we've described before:

As shown, we just need to introduce the parameters outputFile and live into the p0 and p1 text fields in order to perform the dumpHeap operation.

4.2. Programmatic Way

The other way to use the HotSpotDiagnostic MBean is by invoking it programmatically from Java code.

To do so, we first need to get an MBeanServer instance in order to get an MBean that is registered in the application. After that, we simply need to get an instance of a HotSpotDiagnosticMXBean and call its dumpHeap method.

Let's see it in code:

public static void dumpHeap(String filePath, boolean live) throws IOException { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy( server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); mxBean.dumpHeap(filePath, live); }

Notice that an hprof file cannot be overwritten. Therefore, we should take this into account when creating an application that prints heap dumps. If we fail to do so we'll get an exception:

Exception in thread "main" java.io.IOException: File exists at sun.management.HotSpotDiagnostic.dumpHeap0(Native Method) at sun.management.HotSpotDiagnostic.dumpHeap(HotSpotDiagnostic.java:60)

5. Conclusion

In this tutorial, we've shown multiple ways to capture a heap dump in Java.

Als Faustregel sollten wir daran denken, die Option HeapDumpOnOutOfMemoryError immer zu verwenden, wenn Java-Anwendungen ausgeführt werden. Für andere Zwecke kann jedes der anderen Tools perfekt verwendet werden, solange wir den nicht unterstützten Status von jmap berücksichtigen.

Wie immer ist der vollständige Quellcode der Beispiele auf GitHub verfügbar.