有關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