有关JRockit Java堆空间的快速概述,请查阅以下文章:
JRockit Java堆空间
JRCMD工具概述
jrcmd是一个免费工具,可以在JRockit二进制文件中直接使用。 它允许您从运行时JRockit VM生成和收集关键数据,例如:
- Java进程内存空间细分(Java堆与本机内存空间)
- Java堆诊断(直方图)– Java加载的类
- 按需JRockit堆转储生成(仅版本R28 +)
- 线程转储生成
- 更多…
对于本文,我们创建了一个内部泄漏的简单Java程序。 我们将使用该程序来演示如何利用jrcmd进行初始分析。
示例Java内存泄漏程序
这个简单的Java程序只是将String数据添加到静态HashMap中,然后慢慢泄漏到JVM耗尽Java Heap内存的地步。 该程序将允许您通过JRockit jrcmd可视化一个缓慢增长的Java堆泄漏。 请注意,此示例使用了128 MB(-Xms128m –Xmx128m)的Java堆大小。
/*** JavaHeapLeakSimulator* @author Pierre-Hugues Charbonneau* http://javaeesupportpatterns.blogspot.com*/public class JavaHeapLeakSimulator {private final static int NB_ITERATIONS = 500000000;// ~1 KB data footprintprivate final static String LEAKING_DATA_PREFIX = "datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata
datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata";// Map used to stored our leaking String instancesprivate 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 conditionThread.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 –初始执行
可以从托管您要监视的JVM的本地服务器执行JRCMD,也可以通过JRockit Mission Control远程执行。 可执行文件位于您使用的JRockit JDK中:
<JRockit_JDK_HOME>/bin/jrcmd
默认的jrcmd执行将返回您可以监视的活动JRockit Java进程ID的列表:
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 Heap内存使用情况和直方图。 Java堆直方图是Java类实例最大池的快照。 这使您可以查明泄漏的数据类型。 Ple
您可以在print_object_summary(快速摘要)或heap_diagnostics(完全分解)之间选择。
C:\Apps\Weblogic1035\jrockit_160_24_D1.1.2-4\bin>jrcmd 5360 heap_diagnosticsInvoked 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/String2.1% 92k 3941 +92k java/util/HashMap$Entry1.2% 50k 461 +50k java/lang/Class0.8% 35k 21 +35k [Ljava/util/HashMap$Entry;0.6% 24k 7 +24k [B0.3% 15k 305 +15k [Ljava/lang/Object;0.3% 14k 260 +14k java/net/URL0.2% 6k 213 +6k java/util/LinkedHashMap$Entry0.1% 4k 211 +4k java/io/ExpiringCache$Entry0.1% 2k 4 +2k [Ljrockit/vm/FCECache$FCE;0.0% 1k 50 +1k [Ljava/lang/String;0.0% 1k 10 +1k java/lang/Thread0.0% 1k 61 +1k java/util/Hashtable$Entry0.0% 1k 7 +1k [I0.0% 0k 19 +0k java/util/HashMap0.0% 0k 19 +0k java/lang/ref/WeakReference0.0% 0k 7 +0k [Ljava/util/Hashtable$Entry;0.0% 0k 19 +0k java/util/Locale0.0% 0k 11 +0k java/lang/ref/SoftReference0.0% 0k 1 +0k [S
…………………………………………………
–第一列对应于Class对象类型对Java Heap占用量的贡献,以%为单位
–第二列对应于以K为单位的Class对象类型的内存占用量
–第三列对应于特定类型的Class实例的# –第四列对应于特定类型的增量-/ +内存占用量
从上面的快照中可以看到,最大的数据类型是[C(在我们的例子中为char)和java.lang.String。 为了查看泄漏的数据类型,您将需要生成几个快照。 频率将取决于泄漏率。 在我们的示例中,在下面找到5分钟后拍摄的另一个快照:
# After 5 minutes--------- Detailed Heap Statistics: ---------93.9% 26169k 28746 +12032k [C2.4% 674k 28768 +295k java/lang/String2.3% 637k 27219 +295k java/util/HashMap$Entry0.9% 259k 21 +128k [Ljava/util/HashMap$Entry;0.2% 50k 462 +0k java/lang/Class0.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/String2.3% 1148k 49007 +510k java/util/HashMap$Entry0.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 MB增加到28 MB,50 MB,并且还在不断增长……
通过这种方法很容易查明泄漏的数据类型,但是泄漏数据类型的来源(根本原因)呢? 这是jrcmd不再有用的地方。 更深入的内存泄漏分析将要求您使用JRockit Mission Control或堆转储分析(仅JRockit R28 +)。
最后一点,在确定真正的Java Heap泄漏之前,请确保在两次捕获之间至少有一个Full GC之后拍摄了jrcmd快照(您感兴趣的是OldGen泄漏,例如,在主要GC集合中幸存的Java对象)。
JRCMD线程转储生成
线程转储分析对于与卡死的线程相关的问题至关重要,但对于解决某些类型的Java Heap问题也很有用。 例如,它可以通过暴露在短时间内在Java Heap上分配大量内存的罪魁祸首来查明Java Heap突然增加的原因。 可以使用jrcmd print_threads选项生成线程转储。
**在删除Thread.sleep()并增加Java堆容量之后,从我们的示例Java程序捕获了线程转储**
C:\Apps\Weblogic1035\jrockit_160_24_D1.1.2-4\bin>jrcmd 5808 print_threads5808:===== FULL THREAD DUMP ===============Mon Apr 09 09:08:08 2012Oracle 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_blockedat 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程序正在从执行JavaHeapLeakSimulator程序的“主线程”创建许多java.lang.String对象。
结论
我希望本文能帮助您理解可以利用JRockit jrcmd工具进行快速Java堆分析。 期待您的意见和问题。
未来的文章将包括更深入的JRockit Java堆和堆转储分析教程。
参考: Java EE支持模式和Java教程博客上的JCG合作伙伴 Pierre-Hugues Charbonneau的JRockit jrcmd教程 。
翻译自: https://www.javacodegeeks.com/2012/04/jrockit-jrcmd-tutorial.html