Erfassen und analysieren Sie Java-Heap-Dump

Mehvish Ashiq 15 Februar 2024
  1. Einführung in Heap Dump und seine Formate
  2. Beispielcode, der OutOfMemoryError in Java verursacht
  3. Verschiedene Möglichkeiten, Heap Dump zu erfassen
  4. Analysieren Sie den Java-Heap-Dump
Erfassen und analysieren Sie Java-Heap-Dump

Heap-Dumps enthalten eine Momentaufnahme aller Live-Objekte, die die laufende Java-Anwendung auf einem Java-Heap verwendet. Dieses Tutorial informiert über Heap-Dump, seine verschiedenen Formate und seine Bedeutung.

Darüber hinaus werden wir ein Beispiel durchgehen, das OutOfMemoryError demonstriert, was zu verschiedenen Ansätzen zur Erfassung von Heap-Dumps und einem Tool zu deren Analyse führen wird.

Einführung in Heap Dump und seine Formate

Ein Heap enthält alle Objekte, die wir durch Instanziieren einer Klasse erstellen. Jede Klasse der Java-Laufzeitumgebung wird ebenfalls in diesem Heap erstellt.

Dieser Heap wird beim Start von JVM (Java Virtual Machine) erstellt und kann während der Laufzeit erweitert/verkleinert werden, um zerstörte oder in einer Anwendung erstellte Objekte anzupassen.

Der Garbage-Collection-Prozess läuft immer dann, wenn ein Heap voll wird, dieser Prozess sammelt alle Objekte, die nicht mehr verwendet werden, oder wir können sagen, nicht mehr referenziert werden (Sie können mehr über Speicherverwaltung hier finden). Normalerweise werden Heap-Dumps in der hprof-Dateien im Binärformat.

Wir können detaillierte Informationen über jede Objektinstanz abrufen, wie Typ, Klassenname, Adresse, Größe und ob eine Instanz Verweise auf andere Objekte enthält oder nicht. Die Heap-Dumps können in einem der folgenden zwei Formate vorliegen:

  1. Das Portable Heap Dump Format (auch bekannt als PHD-Format)
  2. Das klassische Format

Denken Sie daran, dass der portable Heap-Dump das Standardformat ist und im Binärformat vorliegt, das für die weitere Analyse verarbeitet werden muss. Andererseits ist das klassische Format ASCII-Text, der für Menschen lesbar ist.

Sie können über diese beiden Formate hier lesen.

Bedeutung der Verwendung von Heap Dump

Normalerweise erhalten wir den Vorteil des Heap-Dumps, wenn eine Anwendung aufgrund von OutOfMemoryError abstürzt oder eine Java-Anwendung mehr Speicher verbraucht als erwartet.

Heap-Dump hilft uns, die Hauptursachen für den Fehler und andere Details zu identifizieren, z. B. die Anzahl der Objekte in jeder Klasse, die Speichernutzung für jede Klasse usw.

Es hilft auch bei der Erfassung der Speichergröße, die von jedem Java-Objekt einer Anwendung belegt wird. All diese erfassten Informationen können nützlich sein, um einen tatsächlichen Code zu finden, der Probleme mit Speicherlecks verursacht.

Schauen wir uns ein Codebeispiel an, das OutOfMemoryError verursacht, was zu verschiedenen Möglichkeiten führt, einen Java-Heap-Dump zu erfassen.

Beispielcode, der OutOfMemoryError in Java verursacht

import java.util.ArrayList;
import java.util.List;

public class Test {
  public static void main(String[] args) {
    List<byte[]> myList = new ArrayList<>();
    int index = 0;

    while (true) {
      // 1MB each iteration, 1 x 1024 x 1024 = 1048576
      byte[] bytes = new byte[1048576];
      myList.add(bytes);
      Runtime runTime = Runtime.getRuntime();
      System.out.printf("[%d] free memory is: %s%n", index++, runTime.freeMemory());
    }
  }
}

Der obige Code weist weiterhin Speicher zu, indem er die while-Schleife ausführt, bis ein bestimmter Punkt erreicht ist, an dem Java Virtual Machine nicht genügend Speicher zuordnen kann.

An diesem Punkt erhalten wir den Fehler java.lang.OutOfMemoryError: Java heap space.

...
...
...
[1510] free memory is: 14687728
[1511] free memory is: 12590576
[1512] free memory is: 10493424
[1513] free memory is: 8396272
[1514] free memory is: 6299120
[1515] free memory is: 4201968
[1516] free memory is: 2104320
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at Test.main(Test.java:16)

Hier müssen wir eine Heap-Dump-Analyse durchführen, um die Gründe für OutOfMemoryError zu finden. Dies kann in zwei Schritten erfolgen.

Erfassen Sie zuerst den Heap-Dump und analysieren Sie dann die Heap-Dump-Datei, um die vermuteten Gründe zu finden.

Verschiedene Möglichkeiten, Heap Dump zu erfassen

Es gibt mehrere Möglichkeiten zum Erfassen von Heap-Dumps. Lassen Sie uns das Folgende nacheinander lernen.

  1. jmap
  2. JVisualVM
  3. jcmd
  4. Generieren Sie Heap-Dump automatisch
  5. JMX

Verwenden Sie jmap, um Heap Dump zu erfassen

Das Tool jmap druckt Speicherstatistiken in einer laufenden Java Virtual Machine (JVM); Wir können es auch für entfernte und lokale Prozesse verwenden.

Wir verwenden die Option -dump, um den Heap-Dump mit dem Tool jmap zu erfassen, das wir aus dem Ordner bin des JDK-Home-Verzeichnisses verwenden können.

Syntax:

jmap -dump:[live],format=b,file=<file-path> <pid>

Beispiel:

C:\Program Files\Java\jdk-18\bin> jmap -dump:live,format=b,file=/temp/dump.hprof 12876

Im Folgenden finden Sie eine kurze Beschreibung der Optionen, die wir oben angegeben haben:

Parameter Beschreibung
live Dieser Parameter ist optional; Wenn es gesetzt ist, werden nur Objekte mit aktiven Referenzen gedruckt. Es lässt diejenigen weg, die für die Garbage Collection bereit sind.
format=b Es wird verwendet, um das Format anzugeben, in dem die Dump-Datei gespeichert wird. Hier haben wir b verwendet, was bedeutet, dass diese Dump-Datei im Binärformat vorliegt. Das Ergebnis ist dasselbe, wenn dieser Parameter nicht gesetzt ist.
file Es ist die Datei, in die der Dump geschrieben wird.
pid Es bezeichnet eine ID des Java-Prozesses.

Beachten Sie, dass wir den Befehl jps verwenden können, um pid zu erhalten. Zusätzlich wurde jmap als experimentelles Tool in JDK eingeführt und wird nicht unterstützt; daher müssen Sie in manchen Situationen statt jmap auf andere Tools zurückgreifen.

Verwenden Sie JVisualVM, um Heap Dump zu erfassen

Die JVisualVM ist eine grafische Benutzeroberfläche, mit der wir die Profilerstellung von Java-Anwendungen und die Fehlerbehebung verfolgen können. Es ist einfach, leicht zu bedienen und lässt uns einen Heap-Dump erfassen.

Laut this war es mit Oracle JDK 6, 7 und 8 verfügbar. Ab JDK 9 oder höher wird JVisualVM nicht mehr mit Oracle JDK ausgeliefert; die Benutzer müssen es separat herunterladen, wenn sie es verwenden möchten.

Laden wir es von visualvm.github.io herunter, extrahieren Sie die .zip-Datei, suchen Sie visualvm.exe im Ordner bin, doppelklicken Sie darauf, klicken Sie auf die Schaltfläche I Accept, wenn Sie dazu aufgefordert werden, und Sie werden den folgenden Bildschirm sehen.

Java-Heap-Dump erfassen und analysieren - Visualvm-Startfenster

Unter Lokal werden alle aktuell laufenden Java-Prozesse aufgelistet. Wir können einen Heap Dump erfassen, indem wir den gewünschten Java-Prozess auswählen, mit der rechten Maustaste darauf klicken und die Option Heap Dump wählen.

Es öffnet sich eine neue Registerkarte mit allen notwendigen Informationen.

Verwenden Sie jcmd, um Heap Dump zu erfassen

Dieses Tool befindet sich auch im Ordner bin des Home-Verzeichnisses von JDK; in unserem Fall ist es C:\Program Files\Java\jdk-18\bin. Ihre könnte anders sein, wenn Sie Java nicht am Standardspeicherort installiert haben.

Der jcmd sendet Befehlsanfragen an eine Java Virtual Machine. Denken Sie daran, dass wir es auf derselben Maschine verwenden müssen, auf der ein Java-Prozess ausgeführt wird.

Es hat mehrere Befehle, einer davon ist GC.heap-dump, mit denen wir einen Heap-Dump erfassen, indem wir die Prozess-ID (pid) und einen Pfad für eine Ausgabedatei angeben. Siehe die Syntax des Befehls jcmd unten.

Syntax:

jcmd <pid> GC.head_dump <file-path>

Beispiel:

C:\Program Files\Java\jdk-18\bin> jcmd 12876 GC.head_dump /temp/dump.hprof

Wie jmap generiert es auch den Dump im Binärformat.

Heap-Dump automatisch erfassen

Alle Ansätze, die wir gelernt haben, erfassen den Heap-Dump manuell zu einem bestimmten Zeitpunkt, aber unter Umständen müssen wir einen Heap-Dump erzeugen, sobald java.lang.OutOfMemoryError auftritt.

Hier hilft uns das automatische Generieren eines Heap-Dumps, einen Fehler zu untersuchen.

In Anbetracht dieser Szenarien dient Java mit HeapDumpOnOutOfMemoryError , einer Befehlszeilenoption, die einen Heap-Dump erzeugen kann, wenn eine Anwendung java.lang.OutOfMemoryError auslöst.

java -XX:+HeapDumpOnOutOfMemoryError

Standardmäßig speichert der obige Befehl den Dump in der Datei java_pid<pid>.hprof, die sich dort befindet, wo unsere Anwendung ausgeführt wird. Wir können ein benutzerdefiniertes Verzeichnis oder eine benutzerdefinierte Datei angeben und in einer HeapDumpPath-Option festlegen.

Syntax:

java -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=<file-or-dir-path>

Beispiel:

java -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=/temp/heapdump.bin

Jetzt können wir die erstellte Datei mit dem Heap-Dump wie folgt in Protokollen finden, wenn unserer Anwendung über diese Option der Speicher ausgeht.

java.lang.OutOfMemoryError: Requested array size exceeds VM limit
During heap to java_pid12876.hprof...
  Exception in thread "main" Head dump file created [4745371 bytes in 0.028 secs]
  java.lang.OutOfMemoryError: Requested array size exceeds VM limit

Wir können sehen, dass der obige Text in die Datei java_pid12876.hprof geschrieben wird, und es gibt keinen Overhead, wenn unsere Anwendung mit dieser Option ausgeführt wird.

Es ist gut, diese Option für alle Anwendungen zu verwenden, insbesondere in der Produktion, da Sie nie wissen, wann ein OutOfMemoryError auftritt.

Denken Sie daran, dass wir diese Option zur Laufzeit mit HotSpotDiagnostic MBean verwenden können. Dazu wird JConsole verwendet und die VM-Option HeapDumpOnOutOfMemoryError auf true gesetzt.

Verwenden Sie JMX, um Heap Dump zu erfassen

In dieser Methode verwenden wir HotSpotDiagnostic MBean, das eine dumpHeap-Methode bereitstellt, die die folgenden zwei Parameter akzeptiert:

Parameter Beschreibung
outputFile Es ist ein Pfad einer Ausgabedatei für dump; diese Datei muss die Erweiterung .hprof haben, um Dump zu speichern.
live Wenn wir es auf true setzen, werden nur die aktiven Objekte im Speicher ausgegeben, wie wir bei der Verwendung von jmap in diesem Tutorial gelernt haben.

Wir können es auf zwei Arten aufrufen, um einen Heap-Dump zu erfassen, es programmgesteuert aufrufen oder den JMX-Client wie JConsole verwenden, der sich im bin-Ordner des JDK-Home-Verzeichnisses befindet. Wir werden hier JMX verwenden, aber Sie können hier lernen, wie man es programmgesteuert aufruft.

Die Verwendung von HotSpotDiagnostic MBean über den JMX-Client (JConsole) ist der einfachste Weg, um JConsole zu öffnen, sich mit dem laufenden Java-Prozess zu verbinden, zur Registerkarte MBeans zu navigieren und unter com .Sonnenmanagement.

Wir finden die Methode dumpHeap unter der Dropdown-Liste Operationen, wo wir die Parameter outputFile und live in den Textfeldern p0 und p1 angeben können, um die Operation dumpHeap wie unten gezeigt auszuführen.

Java-Heap-Dump erfassen und analysieren - mbeans

Jetzt ist es an der Zeit, den Java-Heap-Dump zu analysieren.

Analysieren Sie den Java-Heap-Dump

Im Java-Heap-Dump müssen wir nach Objekten mit hohem Speicher, Objektgraphen zum Auffinden von Objekten, die keinen Speicher freigeben und erreichbaren und nicht erreichbaren Objekten suchen.

Der Eclipse Memory Analyzer (MAT) eignet sich am besten zum Analysieren des Java-Heap-Dumps, den wir zuvor generiert haben. Wir starten das Memory Analyzer Tool und öffnen dazu eine Heap-Dump-Datei.

In Eclipse Memory Analyzer (MAT) haben wir zwei Arten von Objektgrößen, die im Folgenden kurz erläutert werden.

  1. Shallow Heap Size – Der flache Heap eines Objekts ist seine Größe im Speicher.
  2. Retained Heap Size – Es ist eine Speichermenge, die freigegeben wird, sobald ein Objekt durch Garbage Collection erfasst wird.

Sobald die Heap-Dump-Datei geöffnet ist, können wir eine Zusammenfassung der Speichernutzung einer Anwendung sehen. Jetzt können wir leicht herausfinden, was OutOfMemoryError verursacht.

Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

Verwandter Artikel - Java Heap