Для быстрого обзора пространства кучи 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" ); 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 .