Forskellige måder at fange Java Heap Dumps på

1. Introduktion

I denne artikel viser vi forskellige måder at fange en bunke dump på Java.

En bunke-dump er et øjebliksbillede af alle de objekter, der er i hukommelsen i JVM på et bestemt tidspunkt. De er meget nyttige til fejlfinding af hukommelseslækageproblemer og optimering af hukommelsesforbrug i Java-applikationer.

Heap-dumps gemmes normalt i hprof-filer i binært format. Vi kan åbne og analysere disse filer ved hjælp af værktøjer som jhat eller JVisualVM. Også for Eclipse-brugere er det meget almindeligt at bruge MAT.

I de næste sektioner gennemgår vi flere værktøjer og tilgange til at generere en bunke dump, og vi viser de største forskelle mellem dem.

2. JDK-værktøjer

JDK leveres med flere værktøjer til at fange bunke-lossepladser på forskellige måder. Alle disse værktøjer er placeret under beholder mappe inde i JDK-hjemmekataloget. Derfor kan vi starte dem fra kommandolinjen, så længe denne mappe er inkluderet i systemstien.

I de næste sektioner viser vi, hvordan du bruger disse værktøjer til at fange bunke-lossepladser.

2.1. jmap

jmap er et værktøj til at udskrive statistik om hukommelse i en kørende JVM. Vi kan bruge det til lokale eller eksterne processer.

For at fange en bunke dump ved hjælp af jmap skal vi bruge dump mulighed:

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

Sammen med denne mulighed skal vi angive flere parametre:

  • Direkte: hvis indstillet, udskrives kun objekter, der har aktive referencer og kasserer dem, der er klar til at blive indsamlet skrald. Denne parameter er valgfri
  • format = b: angiver, at dumpfilen vil være i binært format. Hvis ikke indstillet, er resultatet det samme
  • fil: filen, hvor dumpen skrives til
  • pid: id for Java-processen

Et eksempel ville være sådan:

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

Husk, at vi nemt kan få pid af en Java-proces ved hjælp af jps kommando.

Husk detjmap blev introduceret i JDK som et eksperimentelt værktøj, og det understøttes ikke. Derfor kan det i nogle tilfælde være at foretrække at bruge andre værktøjer i stedet.

2.2. jcmd

jcmd er et meget komplet værktøj, der fungerer ved at sende kommandoanmodninger til JVM. Vi er nødt til at bruge det på den samme maskine, hvor Java-processen kører.

En af dens mange kommandoer er GC.heap_dump. Vi kan bruge det til at få en bunke dump bare ved at specificere pid af processen og outputfilens sti:

jcmd GC.heap_dump 

Vi kan udføre det med de samme parametre, som vi brugte før:

jcmd 12587 GC.heap_dump /tmp/dump.hprof

Som med jmap er den genererede dump i binært format.

2.3. JVisualVM

JVisualVM er et værktøj med en grafisk brugergrænseflade, der lader os overvåge, fejlfinde og profilere Java-applikationer. GUI'en er enkel, men meget intuitiv og nem at bruge.

En af dens mange muligheder giver os mulighed for at fange en bunke dump. Hvis vi højreklikker på en Java-proces og vælger “Heap Dump” mulighed, værktøjet opretter en bunke-dump og åbner den i en ny fane:

Bemærk, at vi kan finde stien til den fil, der er oprettet i “Grundlæggende info” afsnit.

Fra og med JDK 9 er Visual VM ikke inkluderet i Oracle JDK- og Open JDK-distributionerne. Derfor, hvis vi bruger Java 9 eller nyere versioner, kan vi hente JVisualVM fra Visual VM open source-projektwebstedet.

3. Capture a Heap Dump Automatisk

Alle de værktøjer, som vi har vist i de foregående sektioner, er beregnet til at fange bunke dumps manuelt på et bestemt tidspunkt. I nogle tilfælde ønsker vi at få en bunke dump, når en java.lang.OutOfMemoryError opstår, så det hjælper os med at undersøge fejlen.

I disse tilfælde Java leverer HeapDumpOnOutOfMemoryError kommandolinjemulighed, der genererer en bunke-dump, når en java.lang.OutOfMemoryError kastes:

java -XX: + HeapDumpOnOutOfMemoryError

Som standard gemmer det lossepladsen i en java_pid.hprof fil i det bibliotek, hvor vi kører applikationen. Hvis vi vil specificere en anden fil eller mappe, kan vi indstille den i HeapDumpPath mulighed:

java -XX: + HeapDumpOnOutOfMemoryError -XX: HeapDumpPath =

Når vores applikation løber tør for hukommelse ved hjælp af denne mulighed, kan vi se i logfilerne den oprettede fil, der indeholder heapdumpen:

java.lang.OutOfMemoryError: Den anmodede matrixstørrelse overstiger VM-grænsen Dumping af bunke til java_pid12587.hprof ... Undtagelse i tråd "main" Heap-dumpfil oprettet [4744371 bytes i 0,029 sek] java.lang.OutOfMemoryError: Den anmodede arraystørrelse overstiger VM-grænsen på com.baeldung.heapdump.App.main (App.java:7)

I eksemplet ovenfor blev det skrevet til java_pid12587.hprof fil.

Som vi kan se, er denne mulighed meget nyttig og der er ingen omkostninger, når du kører et program med denne mulighed. Derfor anbefales det stærkt at bruge denne mulighed altid, især i produktionen.

Langt om længe, denne mulighed kan også specificeres ved kørsel ved hjælp af HotSpotDiagnostic MBean. For at gøre det kan vi bruge JConsole og indstille HeapDumpOnOutOfMemoryError VM-mulighed til rigtigt:

Vi kan finde flere oplysninger om MBeans og JMX i denne artikel.

4. JMX

Den sidste tilgang, som vi vil dække i denne artikel, bruger JMX. Vi bruger HotSpotDiagnostic MBean som vi kort introducerede i det foregående afsnit. Denne MBean giver en dumpHeap metode der accepterer to parametre:

  • outputFile: stien til filen til dumpen. Filen skal have hprof-udvidelsen
  • Direkte: hvis indstillet til sand, dumpes kun de aktive objekter i hukommelsen, som vi har set med jmap før

I de næste sektioner viser vi 2 forskellige måder at påberåbe sig denne metode for at fange en bunke dump.

4.1. JConsole

Den nemmeste måde at bruge HotSpotDiagnostic MBean er ved hjælp af en JMX-klient såsom JConsole.

Hvis vi åbner JConsole og oprette forbindelse til en kørende Java-proces, vi kan navigere til MBeans fanen og find HotSpotDiagnostic under com.sun.management. I operationer kan vi finde dumpHeap metode, som vi har beskrevet før:

Som vist skal vi bare introducere parametrene outputFile og Direkte ind i p0 og p1 tekstfelter for at udføre dumpHeap operation.

4.2. Programmatisk måde

Den anden måde at bruge HotSpotDiagnostic MBean er ved at påkalde det programmatisk fra Java-kode.

For at gøre det skal vi først få en MBeanServer eksempel for at få et MBean, der er registreret i applikationen. Efter det, vi er simpelthen nødt til at få en forekomst af en HotSpotDiagnosticMXBean og kalde dens dumpHeap metode.

Lad os se det i kode:

offentlig statisk ugyldig dumpHeap (String filePath, boolean live) kaster IOException {MBeanServer server = ManagementFactory.getPlatformMBeanServer (); HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy (server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); mxBean.dumpHeap (filePath, live); }

Bemærk, at en hprof-fil ikke kan overskrives. Derfor bør vi tage dette i betragtning, når vi opretter en applikation, der udskriver dyngdumper. Hvis vi ikke gør det, får vi en undtagelse:

Undtagelse i tråden "main" java.io.IOUndtagelse: Filen findes på sun.management.HotSpotDiagnostic.dumpHeap0 (Native Method) på sun.management.HotSpotDiagnostic.dumpHeap (HotSpotDiagnostic.java:60)

5. Konklusion

I denne vejledning har vi vist flere måder at fange en bunke dump i Java.

Som en tommelfingerregel skal vi huske at bruge HeapDumpOnOutOfMemoryError mulighed altid, når du kører Java-applikationer. Til andre formål kan ethvert af de andre værktøjer bruges perfekt, så længe vi husker jmaps ikke-understøttede status.

Som altid er den fulde kildekode for eksemplerne tilgængelig på GitHub.