javaone_JavaOne 2012:在JVM上诊断应用程序
javaone
值得參加Staffan Larsen (Oracle Java Serviceability Architect)的演講“ 在JVM上診斷您的應(yīng)用程序 ”(Hilton Plaza A / B),只是為了學(xué)習(xí)Oracle JVM 7提供的新jcmd命令行工具。該演示對我來說是“獎(jiǎng)金”,這對我在JavaOne 2012星期三參加的上一屆會(huì)議非常好。Oracle HotSpot JDK提供jcmd,這是一種命令行工具,旨在向后兼容和向前適應(yīng)于Java的未來版本。 它旨在以標(biāo)準(zhǔn)化方式支持新SDK附帶的新工具和功能。 下面的屏幕快照顯示了它用于大多數(shù)基本的類似jps的功能(Larsen幾乎像我剛才提到的那樣提到j(luò)ps ,并將jcmd稱為“類似jps但功能更強(qiáng)大”)。
如上圖所示, jcmd可以像jps一樣使用。
Larsen顯示了jcmd命令的一些方便功能。 他有一些小的Java示例應(yīng)用程序幫助他演示了jcmd。 出于我的目的,我在機(jī)器的一個(gè)終端上運(yùn)行jconsole ,然后針對運(yùn)行jconsole JVM運(yùn)行jcmd命令。 下一個(gè)屏幕快照顯示了基本(無參數(shù)) jcmd調(diào)用如何提供有關(guān)該JConsole進(jìn)程的信息。
jcmd支持按進(jìn)程ID(pid)或按進(jìn)程名稱針對JVM進(jìn)程執(zhí)行。 下一個(gè)屏幕快照顯示了按該名稱針對JConsole進(jìn)程運(yùn)行jcmd并傳遞了該命令help查看可以針對該特定進(jìn)程運(yùn)行哪些選項(xiàng)。 請注意,我嘗試對'dustin'(沒有現(xiàn)有進(jìn)程)運(yùn)行此操作未成功,以證明jcmd確實(shí)顯示了可用于運(yùn)行進(jìn)程的選項(xiàng)。
從上一個(gè)屏幕快照中展示的功能是從Oracle JDK jcmd現(xiàn)有命令行工具遷移到j(luò)cmd的最引人注目的原因之一。 此圖顯示jcmd如何在每個(gè)進(jìn)程的基礎(chǔ)上提供可用選項(xiàng)的列表,從而在支持支持不同/新命令的Java的過去版本或?qū)戆姹痉矫嫣峁┝俗畲蟮撵`活性。
就像jcmd <pid> help (或用進(jìn)程名稱替換pid)列出了jcmd針對特定的JVM進(jìn)程運(yùn)行的可用操作一樣,該相同的幫助機(jī)制也可以針對任何這些列出的特定命令運(yùn)行[使用語法jcmd <pid> <command_name> help (或使用進(jìn)程名稱代替pid)],盡管我無法在Windows計(jì)算機(jī)上使其正常工作。
下圖顯示了針對該JVM進(jìn)程實(shí)際運(yùn)行該命令,而不是簡單地尋求幫助。
在緊接上方的兩個(gè)屏幕快照中,我針對pid(而不是進(jìn)程名稱)運(yùn)行了jcmd ,只是為了表明它既可用于進(jìn)程ID也可用于名稱。 下一個(gè)屏幕快照顯示了對JVM進(jìn)程執(zhí)行jcmd以從JVM進(jìn)程獲取VM標(biāo)志和命令行選項(xiàng)(此JConsole進(jìn)程實(shí)例的pid為3556)。
對支持的JVM進(jìn)程運(yùn)行jcmd的Thread.print命令可以輕松地查看目標(biāo)JVM的線程。 以下輸出是通過對運(yùn)行中的JConsole進(jìn)程運(yùn)行jcmd JConsole Thread.print生成的。
3556: 2012-10-04 23:39:36 Full thread dump Java HotSpot(TM) Client VM (23.2-b09 mixed mode, sharing):'TimerQueue' daemon prio=6 tid=0x024bf000 nid=0x1194 waiting on condition [0x069af000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x23cf2db0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)at java.util.concurrent.DelayQueue.take(DelayQueue.java:209)at javax.swing.TimerQueue.run(TimerQueue.java:171)at java.lang.Thread.run(Thread.java:722)'DestroyJavaVM' prio=6 tid=0x024be400 nid=0x1460 waiting on condition [0x00000000]java.lang.Thread.State: RUNNABLE'AWT-EventQueue-0' prio=6 tid=0x024bdc00 nid=0x169c waiting on condition [0x0525f000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x291a90b0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)at java.awt.EventQueue.getNextEvent(EventQueue.java:521)at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:213)at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)'Thread-2' prio=6 tid=0x024bd800 nid=0x4a8 in Object.wait() [0x04bef000]java.lang.Thread.State: TIMED_WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x2917ed80> (a java.io.PipedInputStream)at java.io.PipedInputStream.read(PipedInputStream.java:327)- locked <0x2917ed80> (a java.io.PipedInputStream)at java.io.PipedInputStream.read(PipedInputStream.java:378)- locked <0x2917ed80> (a java.io.PipedInputStream)at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)- locked <0x29184e28> (a java.io.InputStreamReader)at java.io.InputStreamReader.read(InputStreamReader.java:184)at java.io.BufferedReader.fill(BufferedReader.java:154)at java.io.BufferedReader.readLine(BufferedReader.java:317)- locked <0x29184e28> (a java.io.InputStreamReader)at java.io.BufferedReader.readLine(BufferedReader.java:382)at sun.tools.jconsole.OutputViewer$PipeListener.run(OutputViewer.java:109)'Thread-1' prio=6 tid=0x024bd000 nid=0x17dc in Object.wait() [0x047af000]java.lang.Thread.State: TIMED_WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x29184ee8> (a java.io.PipedInputStream)at java.io.PipedInputStream.read(PipedInputStream.java:327)- locked <0x29184ee8> (a java.io.PipedInputStream)at java.io.PipedInputStream.read(PipedInputStream.java:378)- locked <0x29184ee8> (a java.io.PipedInputStream)at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)- locked <0x2918af80> (a java.io.InputStreamReader)at java.io.InputStreamReader.read(InputStreamReader.java:184)at java.io.BufferedReader.fill(BufferedReader.java:154)at java.io.BufferedReader.readLine(BufferedReader.java:317)- locked <0x2918af80> (a java.io.InputStreamReader)at java.io.BufferedReader.readLine(BufferedReader.java:382)at sun.tools.jconsole.OutputViewer$PipeListener.run(OutputViewer.java:109)'AWT-Windows' daemon prio=6 tid=0x024bc800 nid=0x16e4 runnable [0x0491f000]java.lang.Thread.State: RUNNABLEat sun.awt.windows.WToolkit.eventLoop(Native Method)at sun.awt.windows.WToolkit.run(WToolkit.java:299)at java.lang.Thread.run(Thread.java:722)'AWT-Shutdown' prio=6 tid=0x024bc400 nid=0x157c in Object.wait() [0x04c6f000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x2918b098> (a java.lang.Object)at java.lang.Object.wait(Object.java:503)at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:287)- locked <0x2918b098> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)'Java2D Disposer' daemon prio=10 tid=0x024bbc00 nid=0x3b8 in Object.wait() [0x0482f000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x2918b128> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)- locked <0x2918b128> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)at sun.java2d.Disposer.run(Disposer.java:145)at java.lang.Thread.run(Thread.java:722)'Service Thread' daemon prio=6 tid=0x024bb800 nid=0x1260 runnable [0x00000000]java.lang.Thread.State: RUNNABLE'C1 CompilerThread0' daemon prio=10 tid=0x024c6400 nid=0x120c waiting on condition [0x00000000]java.lang.Thread.State: RUNNABLE'Attach Listener' daemon prio=10 tid=0x024bb000 nid=0x1278 waiting on condition [0x00000000]java.lang.Thread.State: RUNNABLE'Signal Dispatcher' daemon prio=10 tid=0x024bac00 nid=0xe3c runnable [0x00000000]java.lang.Thread.State: RUNNABLE'Finalizer' daemon prio=8 tid=0x024a9c00 nid=0x15c4 in Object.wait() [0x046df000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x2918b358> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)- locked <0x2918b358> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)'Reference Handler' daemon prio=10 tid=0x024a4c00 nid=0xe40 in Object.wait() [0x0475f000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x2917e9c0> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:503)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)- locked <0x2917e9c0> (a java.lang.ref.Reference$Lock)'VM Thread' prio=10 tid=0x024a3800 nid=0x164c runnable 'VM Periodic Task Thread' prio=10 tid=0x024e7c00 nid=0xcf0 waiting on condition JNI global references: 563Larsen展示了如何使用jcmd提供的線程信息來解決死鎖。
Larsen顯示了使用jcmd從正在運(yùn)行的JVM進(jìn)程中獲取類直方圖。 使用命令jcmd <pid> GC.class_histogram完成此操作。 接下來顯示其輸出的一小部分(這次JConsole進(jìn)程的pid為4080)。
4080:num #instances #bytes class name ----------------------------------------------1: 1730 3022728 [I2: 5579 638168 3: 5579 447072 4: 645 340288 5: 4030 337448 [C6: 645 317472 7: 602 218704 8: 942 167280 [B9: 826 97720 java.lang.Class10: 3662 87888 java.lang.String11: 2486 79552 javax.swing.text.html.parser.ContentModel12: 3220 77280 java.util.Hashtable$Entry13: 1180 67168 [S14: 2503 60072 java.util.HashMap$Entry15: 181 59368 16: 971 43584 [Ljava.lang.Object;17: 1053 41160 [[I18: 206 29040 [Ljava.util.HashMap$Entry;19: 111 27880 [Ljava.util.Hashtable$Entry;20: 781 18744 java.util.concurrent.ConcurrentHashMap$HashEntry21: 1069 17104 java.lang.Integer22: 213 9816 [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;23: 202 9696 java.util.HashMap24: 201 9280 [Ljava.lang.String;25: 24 8416 [[ILarsen還演示了jstat及其一些有用的功能。 他演示了jstat -gcnew (新一代行為), jstat -precompilation (編譯方法統(tǒng)計(jì)信息)和jstat -options (顯示選項(xiàng))的用法 。
在演示過程中,Larsen需要將十進(jìn)制數(shù)(pid?) 轉(zhuǎn)換為其十六進(jìn)制表示形式,以便將其與另一個(gè)工具的輸出進(jìn)行比較。 他使用了方便的printf '%x\n' <pid>命令來獲取printf '%x\n' <pid>的十六進(jìn)制表示形式。
Larsen演示了如何使用VisualVM比較兩個(gè)堆轉(zhuǎn)儲(chǔ)并瀏覽一個(gè)堆轉(zhuǎn)儲(chǔ) 。 他還演示了VisualVM Profiler 。
Larsen從先前介紹的旨在運(yùn)行JVM的工具轉(zhuǎn)變?yōu)榭捎糜诜治鯦VM核心文件的工具。 他返回jstack分析核心文件的內(nèi)容。
Larsen談到了通過JMX以及jconsole和jvisualvm類的工具遠(yuǎn)程訪問JVM信息。 他演示了jcmd也可以用于啟動(dòng)JMX jcmd : ManagementServer.start “帶有大量參數(shù)”。 Larsen認(rèn)為,如果今天實(shí)現(xiàn),VisualVM和JConsole將使用ManagementServer.start而不是Attach API。
jstat也可以通過使用jstatd遠(yuǎn)程連接到守護(hù)程序。 沒有使用jstatd加密或身份驗(yàn)證。
jps和jcmd使用“每個(gè)JVM的知名文件”查找系統(tǒng)上正在運(yùn)行的文件:/ hsperfdata_ <user> / <pod>該文件在JVM啟動(dòng)時(shí)創(chuàng)建,在JVM關(guān)閉時(shí)刪除。 未使用的先前文件會(huì)在啟動(dòng)時(shí)被刪除,因此jps和jcmd(作為Java程序本身)將清除這些舊文件。
Attach API “允許發(fā)送“命令”以在JVM中執(zhí)行”,但僅適用于本地計(jì)算機(jī)以及當(dāng)前/相同用戶。 這就是jcmd和jstack用途。 然后,Larsen繼續(xù)說明了將Attach API用于Linux / BSD / Solaris(使用臨時(shí)文件創(chuàng)建)與Windows(使用代碼注入)的不同機(jī)制。 我在Groovy,JMX和Attach API中使用了Attach API 。
診斷命令是“ JVM內(nèi)部的幫助程序”,可產(chǎn)生“文本輸出”。 可以通過jcmd實(shí)用程序(很快通過JMX)執(zhí)行它們。 他們每個(gè)人都有一個(gè)自我描述的工具: jcmd PerfCounter.print可以查看原始內(nèi)容。
Larsen顯示了一張比較“與JVM通訊”方法的信息表: attach , jvmstat , JMX , jstatd和Serviceability Agent (SA)。 SA“應(yīng)被用作最后的手段(通常用于掛起的JVM)”,并使用“調(diào)試器讀取信息”。
Larsen轉(zhuǎn)而談?wù)撐磥淼墓ぞ摺?他從Java Flight Recorder的介紹開始了演示的這一部分。 Java Flight Recorder是“ JVM內(nèi)置的探查器和跟蹤器”,具有“低開銷”并且“始終處于打開狀態(tài)”。 其他即將推出的工具包括Java Mission Control (“圖形工具,提供非常詳細(xì)的運(yùn)行時(shí)監(jiān)視詳細(xì)信息”),針對jcmd更多診斷命令(“出于各種原因最終替換jstack,jmap,jinfo”), JMX 2.0 (“我們正在了解的東西”)再次;它是在很久以前開始的),改進(jìn)了JVM的日志記錄(JVM增強(qiáng)建議[JEP] 158 )和Java發(fā)現(xiàn)協(xié)議(為此即將推出JEP)。
提出的一個(gè)問題是,是否可以像在JConsole中那樣在VisualVM中看到MBean。 正如我在上發(fā)表的文章 ,有一個(gè)VisualVM插件可以做到這一點(diǎn)。
盡管我對Oracle HotSpot JDK命令行工具感到有些滿意,但我并不熟悉jcmd并贊賞Larsen對它的介紹。 在此過程中,我還學(xué)到了其他一些東西。 我唯一的抱怨是Larsen的演講(尤其是演示)是如此Swift,內(nèi)容如此豐富,我希望我能再次看到它。
可以在http://www.oracle.com/javaone/lad-en/session-presentations/corejava/22260-enok-1439100.pdf上找到相關(guān)的(但較舊的)具有相同內(nèi)容的演示文稿。
參考: JavaOne 2012:在我們的JCG合作伙伴 Dustin Marx的Inspired by Actual Events博客上診斷JVM上的應(yīng)用程序 。
JVM 故障排除 2012-10-11
達(dá)斯汀·馬克思翻譯自: https://www.javacodegeeks.com/2012/10/javaone-2012-diagnosing-your.html
javaone
總結(jié)
以上是生活随笔為你收集整理的javaone_JavaOne 2012:在JVM上诊断应用程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓系统的苹果手机能用吗(安卓系统的苹果
- 下一篇: ddos云清洗的相关介绍是什么(ddos