Skip to content

Core Java

wizardjedi edited this page May 16, 2014 · 4 revisions

Снятие HEAP дампа с работающего приложения (используя JMAP)

Получение HEAP-дампа можно произвести как удалённо, используя VisualVM, либо через командную строку, зная PID приложения.

jmap -dump:format=b,file=dump.bin <javaProcessIdHere>

После получения дампа данный файл можно проанализировать либо в VisualVM, либо в Eclips Memory Analyzer Tool ( https://www.eclipse.org/mat/ ). Хотя бывает достаточно посмотреть содержимое дампа с помощью less, чтобы понять какие именно объекты занимают память.

Если дамп не удалось снять, то можно добавить опцию -F - force для снятия дампа.

Во время снятия дампа приложение будет остановлено. Процесс снятия дампа может быть длительным. Например, дампы размером в 1GB снимаются десятки минут.

Снятие HEAP дампа с работающего приложения (используя GDB+JMAP)

На машине должен быть установлен GDB ( sudo apt-get install gdb )

Источник рецепта находится тут: gdb+jmap heap dump.

Кратко рецепт можно описать так:

$ sudo gdb --pid=16837
...
(gdb) gcore /tmp/jvm.core
Saved corefile /tmp/jvm.core
(gdb) detach
(gdb) quit
$ sudo jmap -dump:format=b,file=jvm.hprof /usr/bin/java /tmp/jvm.core
# Which will output...
Attaching to core /tmp/jvm.core from executable /usr/bin/java, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.5-b02
Dumping heap to jvm.hprof ...
...
Heap dump file created

Для удобства авторы рецепта приготовили shell-скрипт (скрипт есть статье или https://gist.github.com/wizardjedi/c1ab6a45615e443278e8) для автоматизации снятия дампов.

$ wget https://gist.githubusercontent.com/wizardjedi/c1ab6a45615e443278e8/raw/gdb-head-dump.sh
$ chmod +x gdb-head-dump.sh
$ ./gdb-head-dump.sh 57464

Приложение тоже "замораживается" на время снятие core-dump'а, но это время гораздо более короткое, чем с случае jmap. Core-dump в 1Gb делается менее секунды. Снятие heap dump'а занимает также много времени, но в данном случае приложение может работать. Так как снятие heap dump'а производится по core dump'у, то этот процесс можно проводить на другой машине.

Анализ heap dump'а с помощью jhat

В состав JVM входит утилита jhat, которая позволяет проводить анализ heap dump'а.

$ jhat dump.hprof 
Reading from dump.hprof...
Dump file created Sun May 04 00:30:12 MSK 2014
Snapshot read, resolving...
Resolving 0 objects...
WARNING:  hprof file does not include java.lang.Class!
WARNING:  hprof file does not include java.lang.String!
WARNING:  hprof file does not include java.lang.ClassLoader!
Chasing references, expect 0 dots
Eliminating duplicate references
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

На порту 7000 запускается web-интерфейс, с помощью которого можно проводить простой анализ heap dump'а.

Средства для анализа heap dump'ов

Получение данных о распределении heap из командной строки

Данные по heap'у

$ jmap -heap 12582
Attaching to process ID 12582, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.7-b01

using thread-local object allocation.
Parallel GC with 18 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 2147483648 (2048.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 536870912 (512.0MB)
   used     = 209724968 (200.00931549072266MB)
   free     = 327145944 (311.99068450927734MB)
   39.06431943178177% used
From Space:
   capacity = 89456640 (85.3125MB)
   used     = 3735568 (3.5625152587890625MB)
   free     = 85721072 (81.74998474121094MB)
   4.175842061584249% used
To Space:
   capacity = 89456640 (85.3125MB)
   used     = 0 (0.0MB)
   free     = 89456640 (85.3125MB)
   0.0% used
PS Old Generation
   capacity = 1431699456 (1365.375MB)
   used     = 24576 (0.0234375MB)
   free     = 1431674880 (1365.3515625MB)
   0.0017165613842351002% used
PS Perm Generation
   capacity = 21757952 (20.75MB)
   used     = 13044608 (12.4403076171875MB)
   free     = 8713344 (8.3096923828125MB)
   59.953289721385545% used

4464 interned Strings occupying 353472 bytes.

Распределение по объектам

$ jmap -histo:live 12582

 num     #instances         #bytes  class name
----------------------------------------------
   1:         24518        3343888  <methodKlass>
   2:         24518        3291816  <constMethodKlass>
   3:          2150        2255808  <constantPoolKlass>
   4:          2150        1609872  <instanceKlassKlass>
   5:          1889        1346912  <constantPoolCacheKlass>
   6:           241         697712  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
   7:          7760         519112  [C
   8:          3680         462440  [B
   9:           107         395104  [Ljava.nio.channels.SelectionKey;
  10:          2345         282400  java.lang.Class
  11:          1392         277456  [Ljava.lang.Object;
  12:           628         255096  <methodDataKlass>
  13:          3101         191336  [S
  14:          7646         183504  java.lang.String
  15:          3366         177632  [[I
  16:          1862         106904  [I
  17:           178         102528  <objArrayKlassKlass>
  18:          2842          90944  java.util.concurrent.ConcurrentHashMap$HashEntry
  19:           623          50960  [Ljava.util.HashMap$Entry;
  20:          1198          38336  java.util.HashMap$Entry
  21:          2305          36880  java.lang.Object
  22:           417          33360  java.lang.reflect.Method
  23:           524          29344  java.util.HashMap
...
Total        111174       16353360

и

$ jmap -histo 12582

 num     #instances         #bytes  class name
----------------------------------------------
   1:          1918      104024464  [I
   2:         24518        3343888  <methodKlass>
   3:         24518        3291816  <constMethodKlass>
   4:          2150        2255808  <constantPoolKlass>
   5:          2150        1609872  <instanceKlassKlass>
   6:          1889        1346912  <constantPoolCacheKlass>
   7:           263         870104  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
   8:          8706         608264  [C
   9:          3905         486576  [B
  10:           112         395264  [Ljava.nio.channels.SelectionKey;
  11:          1502         298104  [Ljava.lang.Object;
  12:          2345         282400  java.lang.Class
  13:           628         255096  <methodDataKlass>
  14:          8195         196680  java.lang.String
  15:          3105         191656  [S
  16:          3366         177632  [[I
  17:           178         102528  <objArrayKlassKlass>
...
Total        120021      120826688

Логирование информации о GC в файл с возможностью ротации файлов журналов

$ java -Xloggc:log/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=128K -jar you_jar.jar

Задаёт вывод информации о GC в файл log/gc.log. Выводиться полная информация о GC. Указываются даты и время GC. Файлы ротируются. Максимальное количество файлов 5, максимальный размер файла 128 Kb.

Вызвать GC из консоли

Существует проект консольной утилиты для JMX. jmxterm https://github.com/jiaqi/jmxterm.git http://wiki.cyclopsgroup.org/jmxterm

$ wget http://downloads.sourceforge.net/cyclops-group/jmxterm-1.0-alpha-4-uber.jar
$ java -jar jmxterm-1.0-alpha-4-uber.jar 
Welcome to JMX terminal. Type "help" for available commands.
$>jvms
31453    ( ) - jmxterm-1.0-alpha-4-uber.jar
12582    ( ) - app1-1.1.jar
17522    ( ) - app2.jar
$>open 12582
#Connection to 12582 is opened
$>bean java.lang:type=Memory
#bean is set to java.lang:type=Memory
$>run gc
#calling operation gc of mbean java.lang:type=Memory
#operation returns: 
null
$>quit
#bye

Однострочная команда

run -b java.lang:type=Memory gc | java -jar jmxterm-1.0-alpha-4-uber.jar -n -l host:port

Кроме того в состав JDK входит утилита JCMD:

jcmd <pid> GC.run

Взято с: http://stackoverflow.com/questions/3523837/how-do-you-force-garbage-collection-from-the-shell

Clone this wiki locally