- Различные способы захвата дампов Java-кучи
- 2. Инструменты JDK
- 2.1. jmap
- 2.2. jcmd
- 2.3. JVisualVM
- 3. Автоматическое создание дампа кучи
- 4. JMX
- 4.1. JConsoleс
- 4.2. Программный способ
- 5. Заключение
- 3.4 Diagnose Leaks in Java Language Code
- 3.4.1 Create a Heap Dump
- 3.4.2 Obtain a Heap Histogram
- 3.4.3 Monitor the Objects Pending Finalization
Различные способы захвата дампов Java-кучи
В этой статье мы покажем различные способы записи дампа кучи на Java.
A heap dump is a snapshot of all the objects that are in memory in the JVM at a certain moment. Они очень полезны для устранения проблем утечки памяти и оптимизации использования памяти в приложениях Java.
Heap dumps are usually stored in binary format hprof files. Мы можем открывать и анализировать эти файлы с помощью таких инструментов, как jhat или JVisualVM. Кроме того, для пользователей Eclipse очень часто используетсяMAT.
В следующих разделах мы рассмотрим несколько инструментов и подходов для создания дампа кучи и покажем основные различия между ними.
2. Инструменты JDK
JDK поставляется с несколькими инструментами для захвата дампов кучи различными способами. All these tools are located under the bin folder inside the JDK home directory. Поэтому мы можем запустить их из командной строки, если этот каталог включен в системный путь.
В следующих разделах мы покажем, как использовать эти инструменты для сбора дампов кучи.
2.1. jmap
jmap — это инструмент для печати статистики о памяти в работающей JVM. Мы можем использовать его для локальных или удаленных процессов.
Чтобы записать дамп кучи с помощью jmap, нам нужно использовать параметрdump:
Наряду с этой опцией, мы должны указать несколько параметров:
- live: если установлено, он печатает только те объекты, которые имеют активные ссылки, и отбрасывает те, которые готовы к сборке мусора. Этот параметр не является обязательным
- format=b: указывает, что файл дампа будет в двоичном формате. Если не установлено, результат будет таким же
- file: файл, в который будет записан дамп
- pid: идентификатор процесса Java
jmap -dump:live,format=b,file=/tmp/dump.hprof 12587
Помните, что мы можем легко получитьpid процесса Java, используя командуjps.
Keep in mind thatjmap was introduced in the JDK as an experimental tool and it’s unsupported. Поэтому в некоторых случаях может быть предпочтительнее использовать вместо этого другие инструменты.
2.2. jcmd
jcmd — это очень полный инструмент, который работает, отправляя запросы команд в JVM. Мы должны использовать его на той же машине, где запущен процесс Java.
One of its many commands is the GC.heap_dump. Мы можем использовать его для получения дампа кучи, просто указавpid процесса и путь к выходному файлу:
Мы можем выполнить его с теми же параметрами, которые мы использовали ранее:
jcmd 12587 GC.heap_dump /tmp/dump.hprof
Как и в случае с jmap, созданный дамп находится в двоичном формате.
2.3. JVisualVM
JVisualVM is a tool with a graphical user interface that lets us monitor, troubleshoot and profile Java applications. Графический интерфейс простой, но очень интуитивно понятный и простой в использовании.
Один из его многочисленных вариантов позволяет нам захватывать дамп кучи. Если щелкнуть правой кнопкой мыши процесс Java и выбрать параметр“Heap Dump”, инструмент создаст дамп кучи и откроет его на новой вкладке:
Обратите внимание, что мы можем найти путь к файлу, созданному в разделе“Basic Info”.
3. Автоматическое создание дампа кучи
Все инструменты, которые мы показали в предыдущих разделах, предназначены для захвата дампов кучи вручную в определенное время. В некоторых случаях мы хотим получить дамп кучи при возникновенииjava.lang.OutOfMemoryError, чтобы это помогло нам исследовать ошибку.
Для этих случаевJava provides the HeapDumpOnOutOfMemoryError command-line option that generates a heap dump when a java.lang.OutOfMemoryError is thrown:
java -XX:+HeapDumpOnOutOfMemoryError
По умолчанию он сохраняет дамп в файлеjava_pid.hprof в каталоге, в котором мы запускаем приложение. Если мы хотим указать другой файл или каталог, мы можем установить его в опцииHeapDumpPath:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=
Когда нашему приложению не хватает памяти, используя эту опцию, мы сможем увидеть в журналах созданный файл, содержащий дамп кучи:
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)
В приведенном выше примере он был записан в файлjava_pid12587.hprof.
Как видим, эта опция очень полезна иthere is no overhead when running an application with this option. Therefore, it’s highly recommended to use this option always, especially in production.
Наконец,this option can also be specified at runtime by using the HotSpotDiagnostic MBean. Для этого мы можем использовать JConsole и установить для параметра виртуальной машиныHeapDumpOnOutOfMemoryError значениеtrue:
Мы можем найти больше информации о MBeans и JMX в этомarticle.
4. JMX
Последний подход, который мы рассмотрим в этой статье, — это использование JMX. We’ll use the HotSpotDiagnostic MBean, который мы кратко представили в предыдущем разделе. This MBean provides a dumpHeap method, который принимает 2 параметра:
- outputFile: путь к файлу для дампа. Файл должен иметь расширение hprof
- live: если установлено значение true, выгружаются только активные объекты в памяти, как мы уже видели с jmap ранее.
В следующих разделах мы покажем 2 различных способа вызова этого метода для записи дампа кучи.
4.1. JConsoleс
Самый простой способ использовать MBeanHotSpotDiagnostic — использовать JMX-клиент, такой как JConsole.
Если мы откроемJConsole и подключимся к работающему процессу Java,we can navigate to the MBeans tab and find the HotSpotDiagnostic under*com.sun.management*. In, мы сможем найти методdumpHeap, который мы описали ранее:
Как показано, нам просто нужно ввести параметрыoutputFile иlive в текстовые поляp0 иp1, чтобы выполнить операциюdumpHeap.
4.2. Программный способ
Другой способ использования MBeanHotSpotDiagnostic — это программный вызов из кода Java.
Для этого нам сначала нужно получить экземплярMBeanServer, чтобы получить MBean, зарегистрированный в приложении. После этогоwe simply need to get an instance of a HotSpotDiagnosticMXBean and call its dumpHeap method.
public static void dumpHeap(String filePath, boolean live) throws IOException
Notice that an hprof file cannot be overwritten. Следовательно, мы должны учитывать это при создании приложения, которое печатает дампы кучи. Если мы этого не сделаем, мы получим исключение:
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. Заключение
В этом руководстве мы показали несколько способов создания дампа кучи на Java.
Как правило, мы должны всегда помнить об использовании параметраHeapDumpOnOutOfMemoryError при запуске приложений Java. Для других целей любой из других инструментов может быть идеально использован, если мы помним о неподдерживаемом статусе jmap.
Как всегда, доступен полный исходный код примеровover on GitHub.
3.4 Diagnose Leaks in Java Language Code
Diagnosing leaks in Java language code can be difficult. Usually, it requires very detailed knowledge of the application. In addition, the process is often iterative and lengthy. This section provides information about the tools you can use to diagnose memory leaks in Java language code.
The following are two utilities used to diagnose leaks in Java language code.
- The NetBeans Profiler: The NetBeans Profiler can locate memory leaks very quickly. Commercial memory leak debugging tools may take a long time to locate a leak in a large application. The NetBeans Profiler, however, uses the pattern of memory allocations and reclamations that such objects typically demonstrate. This process includes also the lack of memory reclamations. The profiler can check where these objects were allocated, which often is sufficient to identify the root cause of the leak. For more details, see NetBeans Profiler.
- The jhat utility: The jhat utility is useful when debugging unintentional object retention (or memory leaks). It provides a way to browse an object dump, view all reachable objects in the heap, and understand which references are keeping an object alive. To use jhat you must obtain one or more heap dumps of the running application, and the dumps must be in binary format. After the dump file is created, it can be used as input to jhat . See The jhat Utility.
The following sections describe the other ways to diagnose leaks in Java language code.
3.4.1 Create a Heap Dump
A heap dump provides detailed information about the allocation of heap memory. There are several ways to create a heap dump:
- HPROF can create a heap dump if it is launched with the application. Example 3-1 shows the usage of the command.
$ java -agentlib:hprof=file=snapshot.hprof,format=b application
Note: If the JVM is embedded or is not started using a command-line launcher that allows additional options to be provided, then it might be possible to use the JAVA_TOOLS_OPTIONS environment variable so that the -agentlib option is automatically added to the command line. See The JAVA_TOOL_OPTIONS Environment Variable for further information about this environment variable. |
jcmd GC.heap_dump filename=Myheapdump
$ jmap -dump:format=b,file=snapshot.jmap pid
3.4.2 Obtain a Heap Histogram
You can try to quickly narrow down a memory leak by examining the heap histogram. It can be obtained in several ways:
- If the Java process is started with the -XX:+PrintClassHistogram command-line option, then the Control+Break handler will produce a heap histogram.
- You can use the jmap utility to obtain a heap histogram from a running process: It is recommended to use the latest utility, jcmd instead of jmap utility for enhanced diagnostics and reduced performance overhead. See Useful Commands for jcmd Utility.The command in Example 3-4 creates a heap histogram for a running process using jcmd and results similar to the following jmap command.
jcmd GC.class_histogram filename=Myheaphistogram
For example, if you specify the -XX:+HeapDumpOnOutOfMemoryError command-line option while running your application, then when an OutOfMemoryError exception is thrown, the JVM will generate a heap dump. You can then execute jmap on the core file to get a histogram, as shown in Example 3-6.
$ jmap -histo \ /java/re/javase/6/latest/binaries/solaris-sparc/bin/java core.27421
Attaching to core core.27421 from executable /java/re/javase/6/latest/binaries/solaris-sparc/bin/java, please wait. Debugger attached successfully. Server compiler detected. JVM version is 1.6.0-beta-b63 Iterating over heap. This may take a while. Heap traversal took 8.902 seconds. Object Histogram: Size Count Class description ------------------------------------------------------- 86683872 3611828 java.lang.String 20979136 204 java.lang.Object[] 403728 4225 * ConstMethodKlass 306608 4225 * MethodKlass 220032 6094 * SymbolKlass 152960 294 * ConstantPoolKlass 108512 277 * ConstantPoolCacheKlass 104928 294 * InstanceKlassKlass 68024 362 byte[] 65600 559 char[] 31592 359 java.lang.Class 27176 462 java.lang.Object[] 25384 423 short[] 17192 307 int[] :
3.4.3 Monitor the Objects Pending Finalization
When the OutOfMemoryError exception is thrown with the «Java heap space» detail message, the cause can be excessive use of finalizers. To diagnose this, you have several options for monitoring the number of objects that are pending finalization:
- The JConsole management tool can be used to monitor the number of objects that are pending finalization. This tool reports the pending finalization count in the memory statistics on the Summary tab pane. The count is approximate, but it can be used to characterize an application and understand if it relies a lot on finalization.
- On Oracle Solaris and Linux operating systems, the jmap utility can be used with the -finalizerinfo option to print information about objects awaiting finalization.
- An application can report the approximate number of objects pending finalization using the getObjectPendingFinalizationCount method of the java.lang.management.MemoryMXBean class. Links to the API documentation and example code can be found in Custom Diagnostic Tools. The example code can easily be extended to include the reporting of the pending finalization count.
See Finalization and Weak, Soft, and Phantom References in Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide for information about detecting and migrating from finalization.