1. Въведение
В тази статия ще покажем различни начини за заснемане на купчина в Java.
Дъмпингът на купчина е моментна снимка на всички обекти, които са в паметта в JVM в определен момент . Те са много полезни за отстраняване на проблеми с изтичане на памет и оптимизиране на използването на памет в Java приложения.
Изхвърлянията на купчина обикновено се съхраняват във файлове с двоичен формат hprof. Можем да отваряме и анализираме тези файлове с помощта на инструменти като jhat или JVisualVM. Също така, за потребителите на Eclipse е много често да се използва MAT.
В следващите раздели ще разгледаме множество инструменти и подходи за генериране на купчина и ще покажем основните разлики между тях.
2. Инструменти JDK
JDK се предлага с няколко инструмента за улавяне на сметища по различни начини. Всички тези инструменти се намират под папката bin в домашната директория на JDK . Следователно можем да ги стартираме от командния ред, стига тази директория да е включена в системния път.
В следващите раздели ще покажем как да използвате тези инструменти, за да заснемете купчини.
2.1. jmap
jmap е инструмент за отпечатване на статистика за паметта в работещ JVM. Можем да го използваме за локални или отдалечени процеси.
За да направите един куп сметище използване jmap ние трябва да се използва сметището вариант:
jmap -dump:[live],format=b,file=
Заедно с тази опция трябва да посочим няколко параметъра:
- на живо : ако го зададете, той отпечатва само обекти, които имат активни препратки и изхвърля тези, които са готови за събиране на боклука. Този параметър не е задължителен
- format = b : указва, че изхвърлящият файл ще бъде в двоичен формат. Ако не е зададен, резултатът е същият
- файл : файлът, в който ще бъде записан дъмпът
- pid : идентификатор на процеса на Java
Пример може да бъде по следния начин:
jmap -dump:live,format=b,file=/tmp/dump.hprof 12587
Не забравяйте, че можем лесно да получим pid на Java процес с помощта на jps командата.
Имайте предвид, че jmap е въведен в JDK като експериментален инструмент и не се поддържа. Следователно, в някои случаи може да е за предпочитане вместо това да се използват други инструменти.
2.2. jcmd
jcmd е много пълен инструмент, който работи чрез изпращане на заявки за команди до JVM. Трябва да го използваме в същата машина, където се изпълнява процесът Java.
Една от многото му команди е GC.heap_dump . Можем да го използваме, за да получим купчина само, като посочим pid на процеса и пътя на изходния файл:
jcmd GC.heap_dump
Можем да го изпълним със същите параметри, които използвахме преди:
jcmd 12587 GC.heap_dump /tmp/dump.hprof
Както при jmap, генерираният дъмп е в двоичен формат.
2.3. JVisualVM
JVisualVM е инструмент с графичен потребителски интерфейс, който ни позволява да наблюдаваме, отстраняваме и профилираме Java приложения . GUI е прост, но много интуитивен и лесен за използване.
Една от многото му опции ни позволява да заснемем купчина. Ако щракнем с десния бутон на мишката върху процес на Java и изберете опцията “Heap Dump” , инструментът ще създаде купчина и ще го отвори в нов раздел:

Забележете, че можем да намерим пътя на файла, създаден в раздела „Основна информация“ .
Започвайки от JDK 9, Visual VM не е включен в дистрибуциите на Oracle JDK и Open JDK. Следователно, ако използваме Java 9 или по-нови версии, можем да вземем JVisualVM от сайта за проекти с отворен код Visual VM.
3. Заснемете автоматично изхвърляне на купчина
All the tools that we've shown in the previous sections are intended to capture heap dumps manually at a specific time. In some cases, we want to get a heap dump when a java.lang.OutOfMemoryError occurs so it helps us investigate the error.
For these cases, Java provides the HeapDumpOnOutOfMemoryError command-line option that generates a heap dump when a java.lang.OutOfMemoryError is thrown:
java -XX:+HeapDumpOnOutOfMemoryError
By default, it stores the dump in a java_pid.hprof file in the directory where we're running the application. If we want to specify another file or directory we can set it in the HeapDumpPath option:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=
When our application runs out of memory using this option, we'll be able to see in the logs the created file that contains the heap dump:
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)
In the example above, it was written to the java_pid12587.hprof file.
As we can see, this option is very useful and there is no overhead when running an application with this option. Therefore, it's highly recommended to use this option always, especially in production.
Finally, this option can also be specified at runtime by using the HotSpotDiagnostic MBean. To do so, we can use JConsole and set the HeapDumpOnOutOfMemoryError VM option to true:

We can find more information about MBeans and JMX in this article.
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.
Като правило, трябва да помним да използваме опцията HeapDumpOnOutOfMemoryError винаги, когато стартираме Java приложения. За други цели всеки друг инструмент може да бъде перфектно използван, стига да имаме предвид неподдържаното състояние на jmap.
Както винаги, пълният изходен код на примерите е достъпен в GitHub.