Статьи

JRockit JRCMD учебник

Эта статья предоставит вам обзор и учебное пособие о том, как вы можете выполнить первоначальный анализ и изоляцию проблемы Java-кучи JRockit с помощью инструмента jrcmd. Более глубокий анализ и учебное пособие с использованием JRockit Mission Control и анализа дампа кучи (только версия JRockit R28 +) будут рассмотрены в следующих статьях.

Для быстрого обзора пространства кучи Java JRockit, пожалуйста, обратитесь к статье ниже:
JRockit Java Heap Space

Обзор инструмента JRCMD

jrcmd — это бесплатный инструмент, который доступен в бинарных файлах JRockit. Это позволяет вам генерировать и собирать важные данные из вашей виртуальной машины JRockit, такие как:

  • Распределение памяти в процессе Java (Java Heap против собственной памяти)
  • Диагностика кучи Java (гистограмма) — загруженные классы Java
  • Создание дампа кучи JRockit по требованию (только версия R28 +)
  • Создание дампа потока
  • Больше…

Для этой статьи мы создали простую Java-программу, внутреннюю утечку. Мы будем использовать эту программу, чтобы продемонстрировать, как вы можете использовать jrcmd для первоначального анализа.

Пример программы утечки памяти Java

Эта простая Java-программа просто добавляет данные String в статический HashMap и медленно перетекает в точку, в которой JVM не хватает памяти Java Heap. Эта программа позволит вам визуализировать медленно растущую утечку Java Heap через JRockit jrcmd. Обратите внимание, что для этого примера использовалась куча Java размером 128 МБ (-Xms128m –Xmx128m).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
  
 * JavaHeapLeakSimulator
 * @author Pierre-Hugues Charbonneau
 */
  
public class JavaHeapLeakSimulator {
  
        private final static int NB_ITERATIONS = 500000000;
        // ~1 KB data footprint
  
        private final static String LEAKING_DATA_PREFIX = "datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata";
  
        // Map used to stored our leaking String instances
        private static Map<String, String> leakingMap;
 
        static {
               leakingMap = new HashMap<String, String>();
        }
  
       /**
  
         * @param args
  
         */
  
        public static void main(String[] args) {
  
               System.out.println("Java Heap Leak Simulator 1.0");
               System.out.println("Author: Pierre-Hugues Charbonneau");
               System.out.println("http://javaeesupportpatterns.blogspot.com/");
  
               try {
  
                       for (int i = 0; i < NB_ITERATIONS; i++) {
 
                              String data = LEAKING_DATA_PREFIX + i;
                                
                              // Add data to our leaking Map data structure...
                              leakingMap.put(data, data);                            
 
                              // Slowdown the Java program so we can monitor the leak before the OutOfMemoryError condition
                              Thread.sleep(1);
  
                       }
 
               } catch (Throwable any) {
 
                       if (any instanceof java.lang.OutOfMemoryError) {
                              System.out.println("OutOfMemoryError triggered! "
                                             + any.getMessage() + " [" + any + "]");
                       } else {
  
                              System.out.println("Unexpected Exception! " + any.getMessage()
                                             + " [" + any + "]");
                       }
               }
 
               System.out.println("JavaHeapLeakSimulator done!");
        }
}

JRCMD — начальное исполнение

JRCMD может быть запущен с локального сервера, на котором размещена JVM, которую вы хотите отслеживать, или удаленно через JRockit Mission Control. Исполняемый файл расположен в Jock JRockit, который вы используете:

1
<JRockit_JDK_HOME>/bin/jrcmd

Выполнение jrcmd по умолчанию вернет список активных идентификаторов Java-процессов JRockit, которые вы можете отслеживать:

1
2
3
4
C:\Apps\Weblogic1035\jrockit_160_24_D1.1.2-4\bin>jrcmd
5360 org.ph.javaee.tool.oom.JavaHeapLeakSimulator
5952
6852 jrockit.tools.jrcmd.JrCmd

JRCMD — мониторинг кучи Java

Следующий шаг — начать мониторинг использования памяти и гистограммы кучи Java. Гистограмма Java Heap — это снимок самых больших пулов экземпляров Java Class. Это позволит вам точно определить тип данных утечки. Пле

Вы можете выбрать между print_object_summary (быстрая сводка) или heap_diagnostics (полная разбивка).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
C:\Apps\Weblogic1035\jrockit_160_24_D1.1.2-4\bin>jrcmd 5360 heap_diagnostics
  
Invoked from diagnosticcommand
  
======== BEGIN OF HEAPDIAGNOSTIC =========================
  
Total memory in system: 8465022976 bytes
Available physical memory in system: 5279170560 bytes
-Xmx (maximal heap size) is 134217728 bytes
Heapsize: 134217728 bytes
Free heap-memory: 123592704 bytes
  
 
 
--------- Detailed Heap Statistics: ---------
  
90.9% 3948k     5468  +3948k [C
 3.0% 128k     5490   +128k java/lang/String
 2.1% 92k     3941    +92k java/util/HashMap$Entry
 1.2% 50k      461    +50k java/lang/Class
 0.8% 35k       21    +35k [Ljava/util/HashMap$Entry;
 0.6% 24k        7    +24k [B
 0.3% 15k      305    +15k [Ljava/lang/Object;
 0.3% 14k      260    +14k java/net/URL
 0.2% 6k      213     +6k java/util/LinkedHashMap$Entry
 0.1% 4k      211     +4k java/io/ExpiringCache$Entry
 0.1% 2k        4     +2k [Ljrockit/vm/FCECache$FCE;
 0.0% 1k       50     +1k [Ljava/lang/String;
 0.0% 1k       10     +1k java/lang/Thread
 0.0% 1k       61     +1k java/util/Hashtable$Entry
 0.0% 1k        7     +1k [I
 0.0% 0k       19     +0k java/util/HashMap
 0.0% 0k       19     +0k java/lang/ref/WeakReference
 0.0% 0k        7     +0k [Ljava/util/Hashtable$Entry;
 0.0% 0k       19     +0k java/util/Locale
 0.0% 0k       11     +0k java/lang/ref/SoftReference
 0.0% 0k        1     +0k [S
…………………………………………………

— Первый столбец соответствует вкладу типа объекта Class в размер кучи Java в%
— Второй столбец соответствует размеру памяти в классе объектов класса K
— Третий столбец соответствует # экземплярам класса определенного типа.
— Четвертый столбец соответствует размеру памяти дельта — / + определенного типа

Как видно из приведенного выше снимка, самый большой тип данных — это [C (char в нашем случае) & java.lang.String. Чтобы увидеть, какие типы данных просочились, вам нужно сгенерировать несколько снимков. Частота будет зависеть от скорости утечки. В нашем примере найдите еще один снимок, сделанный через 5 минут:

01
02
03
04
05
06
07
08
09
10
# After 5 minutes
  
--------- Detailed Heap Statistics: ---------
  
93.9% 26169k    28746 +12032k [C
 2.4% 674k    28768   +295k java/lang/String
 2.3% 637k    27219   +295k java/util/HashMap$Entry
 0.9% 259k       21   +128k [Ljava/util/HashMap$Entry;
 0.2% 50k      462     +0k java/lang/Class
 0.1% 24k        7     +0k [B
1
2
3
4
5
6
7
8
9
# After 5 more minutes
  
--------- Detailed Heap Statistics: ---------
  
94.5% 46978k    50534 +20809k [C
 2.4% 1184k    50556   +510k java/lang/String
 2.3% 1148k    49007   +510k java/util/HashMap$Entry
 0.5% 259k       21     +0k [Ljava/util/HashMap$Entry;
 0.1% 50k      462     +0k java/lang/Class

Третий и четвертый столбцы показывают постоянный рост. Как вы можете видеть, в нашем случае утечка данных — это [C, java.lang.String и java.util.HashMap $ Entry, которые увеличились с ~ 4 МБ до 28 МБ, 50 МБ и растут…

При таком подходе легко определить тип (ы) утечки данных, но как насчет источника (первопричины) типа (ов) утечки? Здесь jrcmd больше не нужен. Более глубокий анализ утечек памяти потребует от вас использовать либо JRockit Mission Control, либо анализ дампа кучи (только JRockit R28 +).

В заключение, прежде чем вы сможете сделать вывод об истинной утечке кучи Java, убедитесь, что моментальные снимки jrcmd делаются после хотя бы одного полного GC между перехватами (что вас интересует, это утечка OldGen, например, объекты Java, сохранившиеся в основных коллекциях GC).

Генерация дампа потоков JRCMD

Анализ дампа потока имеет решающее значение для застрявших проблем, связанных с потоками, но также может быть полезен для устранения некоторых типов проблем Java Heap. Например, он может точно определить источник внезапного увеличения кучи Java, обнажив виновный поток (ы), выделяющий большой объем памяти на кучи Java за короткий промежуток времени. Дамп потока может быть сгенерирован с помощью опции jrcmd print_threads.

** Дамп потока, полученный из нашей программы Java после удаления Thread.sleep () и увеличения емкости кучи Java **

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
C:\Apps\Weblogic1035\jrockit_160_24_D1.1.2-4\bin>jrcmd 5808 print_threads
  
5808:
  
 
 
 
===== FULL THREAD DUMP ===============
  
Mon Apr 09 09:08:08 2012
  
Oracle JRockit(R) R28.1.3-11-141760-1.6.0_24-20110301-1429-windows-ia32
"Main Thread" id=1 idx=0x4 tid=6076 prio=5 alive, native_blocked
    at jrockit/vm/Allocator.getNewTla(II)V(Native Method)
    at jrockit/vm/Allocator.allocObjectOrArray(Allocator.java:354)[optimized]
    at java/util/Arrays.copyOfRange(Arrays.java:3209)[inlined]
    at java/lang/String.<init>(String.java:215)[inlined]
    at java/lang/StringBuilder.toString(StringBuilder.java:430)[optimized]
    at org/ph/javaee/tool/oom/JavaHeapLeakSimulator.main(JavaHeapLeakSimulator.java:38)
    at jrockit/vm/RNI.c2java(IIIII)V(Native Method)
    -- end of trace
……………………………………….

Мы можем видеть, что наша примерная Java-программа создает множество объектов java.lang.String из «Основного потока», выполняющего нашу программу JavaHeapLeakSimulator.

Вывод

Я надеюсь, что эта статья помогла вам понять, что вы можете использовать инструмент JRockit jrcmd для быстрого анализа кучи Java. Я с нетерпением жду ваших комментариев и вопросов.

Будущие статьи будут включать более глубокое руководство по анализу Java-кучи и дампа кучи JRockit.

Ссылка: учебное руководство по JRockit jrcmd от нашего партнера по JCG Пьера-Хьюга Шарбонно в блоге по шаблонам поддержки Java EE и учебному пособию по Java .