Различные способы захвата дампов Java-кучи

Различные способы захвата дампов Java-кучи

1. Вступление

В этой статье мы покажем различные способы записи дампа кучи на 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:

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

Наряду с этой опцией, мы должны указать несколько параметров:

  • 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  GC.heap_dump 

Мы можем выполнить его с теми же параметрами, которые мы использовали ранее:

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”, инструмент создаст дамп кучи и откроет его на новой вкладке:

image

Обратите внимание, что мы можем найти путь к файлу, созданному в разделе“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<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:

image

Мы можем найти больше информации о 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, который мы описали ранее:

image

Как показано, нам просто нужно ввести параметры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 {
    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. Следовательно, мы должны учитывать это при создании приложения, которое печатает дампы кучи. Если мы этого не сделаем, мы получим исключение:

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.