Эта статья предоставит вам обзор и учебное пособие о том, как вы можете выполнить первоначальный анализ и изоляцию проблемы Java-кучи JRockit с помощью инструмента jrcmd. Более глубокий анализ и учебное пособие с использованием JRockit Mission Control и анализа дампа кучи (только версия JRockit R28 +) будут рассмотрены в следующих статьях.
Для быстрого обзора пространства кучи Java JRockit, пожалуйста, обратитесь к статье ниже:
Место кучи Java JRockit
Обзор инструмента 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).
/** * JavaHeapLeakSimulator * @author Pierre-Hugues Charbonneau * http://javaeesupportpatterns.blogspot.com */ public class JavaHeapLeakSimulator { private final static int NB_ITERATIONS = 500000000; // ~1 KB data footprint private final static String LEAKING_DATA_PREFIX = "datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata"; // 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. Исполняемый файл находится в используемом вами JRockit JDK:
<JRockit_JDK_HOME> / bin / jrcmd
Выполнение jrcmd по умолчанию вернет список идентификатора активного процесса Java JRitit, который вы можете отслеживать:
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. Это позволит вам точно определить тип данных утечки. Ple
Вы можете выбрать между print_object_summary (краткая сводка) или heap_diagnostics (полная разбивка).
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 в%
— Второй столбец соответствует фрагменту памяти типа объекта Class в K
— Третий столбец соответствует # экземплярам Class определенного типа
— Четвертый столбец соответствует размеру памяти delta — / + определенного типа.
Как видно из приведенного выше снимка, самый большой тип данных — это [C (char в нашем случае) & java.lang.String. Чтобы увидеть, какие типы данных просочились, вам нужно сгенерировать несколько снимков. Частота будет зависеть от скорости утечки. В нашем примере найдите еще один снимок, сделанный через 5 минут:
# 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 # 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.
** Thread Dump captured from our sample Java program after removing the Thread.sleep() and increasing the Java Heap capacity ** 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.