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

Verschiedene Möglichkeiten zur Erfassung von Java-Heap-Dumps

1. Einführung

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

A heap dump is a snapshot of all the objects that are in memory in the JVM at a certain moment. Sie sind sehr nützlich, um Probleme mit Speicherverlusten zu beheben und die Speichernutzung in Java-Anwendungen zu optimieren.

Heap dumps are usually stored in binary format hprof files. 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 verschiedene Tools und Ansätze zum Generieren eines Heap-Dumps durchgehen und die Hauptunterschiede zwischen ihnen aufzeigen.

2. JDK-Tools

Das JDK wird mit mehreren Tools geliefert, mit denen sich Heap-Dumps auf unterschiedliche Weise erfassen lassen. All these tools are located under the bin folder inside the JDK home directory. Daher können wir sie von der Befehlszeile aus 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 Arbeitsspeicher 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 Optiondump verwenden:

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

Zusammen mit dieser Option sollten wir mehrere Parameter angeben:

  • live: Wenn diese Option festgelegt ist, werden nur Objekte mit aktiven Referenzen gedruckt und diejenigen verworfen, die für die Speicherbereinigung bereit sind. Dieser Parameter ist optional

  • format=b: Gibt an, dass die Speicherauszugsdatei im Binärformat vorliegt. Wenn nicht, ist das Ergebnis dasselbe

  • file: 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 mit dem Befehljps leicht diepid eines Java-Prozesses abrufen können.

Keep in mind thatjmap was introduced in the JDK as an experimental tool and it’s unsupported. Daher kann es in einigen Fällen vorzuziehen sein, stattdessen andere Werkzeuge 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.

One of its many commands is the GC.heap_dump. Wir können es verwenden, um einen Heap-Dump zu erhalten, indem wir nur diepid 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 Dump im Binärformat vor.

2.3. JVisualVM

JVisualVM is a tool with a graphical user interface that lets us monitor, troubleshoot and profile Java applications. Die Benutzeroberfläche ist einfach, aber sehr intuitiv und einfach zu bedienen.

Mit einer der vielen Optionen können wir einen Heap-Dump 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:

image

Beachten Sie, dass wir den Pfad der erstellten Datei im Abschnitt“Basic Info” finden.

3. Erfassen Sie einen Heap Dump automatisch

Alle Tools, die wir in den vorherigen Abschnitten gezeigt haben, sollen Heap-Dumps zu einem bestimmten Zeitpunkt manuell erfassen. In einigen Fällen möchten wir einen Heap-Dump erhalten, wenn einjava.lang.OutOfMemoryError auftritt, damit wir den Fehler untersuchen können.

In diesen FällenJava provides the HeapDumpOnOutOfMemoryError command-line option that generates a heap dump when a java.lang.OutOfMemoryError is thrown:

java -XX:+HeapDumpOnOutOfMemoryError

Standardmäßig wird der Speicherauszug in einerjava_pid<pid>.hprof-Datei 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 OptionHeapDumpPath 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.example.heapdump.App.main(App.java:7)

Im obigen Beispiel wurde es in die Dateijava_pid12587.hprofgeschrieben.

Wie wir sehen können, ist diese Option sehr nützlich undthere is no overhead when running an application with this option. Therefore, it’s highly recommended to use this option always, especially in production.

Schließlichthis option can also be specified at runtime by using the HotSpotDiagnostic MBean. Dazu können wir JConsole verwenden und die VM-OptionHeapDumpOnOutOfMemoryError auftrue setzen:

image

Weitere Informationen zu MBeans und JMX finden Sie inarticle.

4. JMX

Der letzte Ansatz, den wir in diesem Artikel behandeln, ist die Verwendung von JMX. We’ll use the HotSpotDiagnostic MBean, die wir im vorherigen Abschnitt kurz vorgestellt haben. This MBean provides a dumpHeap method, das 2 Parameter akzeptiert:

  • outputFile: Der Pfad der Datei für den Speicherauszug. Die Datei sollte die Erweiterung hprof haben

  • live: Wenn auf true gesetzt, werden nur die aktiven Objekte im Speicher ausgegeben, wie wir zuvor bei jmap gesehen haben

In den nächsten Abschnitten werden zwei verschiedene Möglichkeiten zum Aufrufen dieser Methode gezeigt, um einen Heap-Dump zu erfassen.

4.1. JConsole

Der einfachste Weg, die MBean vonHotSpotDiagnosticzu verwenden, ist die Verwendung eines JMX-Clients wie JConsole.

Wenn wirJConsole öffnen und eine Verbindung zu einem laufenden Java-Prozess herstellen,we can navigate to the MBeans tab and find the HotSpotDiagnostic under*com.sun.management*. In-Operationen, können wir die zuvor beschriebenedumpHeap-Methode finden:

image

Wie gezeigt, müssen wir nur die ParameteroutputFile undlive in die Textfelderp0 undp1 einfügen, um die OperationdumpHeap auszuführen.

4.2. Programmatischer Weg

Die andere Möglichkeit, die MBean vonHotSpotDiagnosticzu verwenden, besteht darin, sie programmgesteuert aus Java-Code aufzurufen.

Dazu müssen wir zuerst eineMBeanServer-Instanz abrufen, um eine MBean zu erhalten, die in der Anwendung registriert ist. Danachwe simply need to get an instance of a HotSpotDiagnosticMXBean and call its dumpHeap method.

Sehen wir es uns im Code an:

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. Daher sollten wir dies berücksichtigen, wenn wir eine Anwendung erstellen, die Heap-Dumps druckt. Wenn wir dies nicht tun, erhalten wir eine Ausnahme:

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. Fazit

In diesem Tutorial haben wir verschiedene Möglichkeiten gezeigt, wie Sie einen Heap-Dump in Java erfassen können.

Als Faustregel sollten wir daran denken, die OptionHeapDumpOnOutOfMemoryErrorimmer 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 Beispieleover on GitHub verfügbar.