JavaOne 2012:在JVM上诊断应用程序
Oracle HotSpot JDK提供了jcmd,這是一種命令行工具,旨在向后兼容和向前適應于Java的未來版本。 它旨在以標準化方式支持新SDK附帶的新工具和功能。 下面的屏幕快照顯示了它用于大多數基本的類似于jps的功能(Larsen幾乎像我剛才提到的那樣提到jps ,并將jcmd稱為“類似于jps但功能更強大”)。
如上圖所示, jcmd可以像jps一樣使用。
Larsen顯示了jcmd命令的一些方便功能。 他有一些小樣本Java應用程序幫助他演示了jcmd。 出于我的目的,我在計算機的一個終端中運行jconsole ,然后針對運行jconsole JVM運行jcmd命令。 下一個屏幕快照顯示了基本(無參數) jcmd調用如何提供有關該JConsole進程的信息。
jcmd支持按進程ID(pid)或按進程名稱針對JVM進程執行。 下一個屏幕快照顯示了按該名稱針對JConsole進程運行jcmd并將其傳遞給help以查看可以針對該特定進程運行哪些選項。 請注意,我嘗試針對“ dustin”(沒有現有進程)運行此命令失敗,以證明jcmd確實顯示了可用于運行進程的選項。
從上一個屏幕快照中展示的功能是從Oracle JDK jcmd現有命令行工具遷移到jcmd的最引人注目的原因之一。 此圖顯示jcmd如何在每個進程的基礎上提供可用選項的列表,從而在支持支持不同/新命令的Java的過去版本或將來版本方面提供了最大的靈活性。
就像jcmd <pid> help (或用進程名稱替換pid)列出了jcmd針對特定的JVM進程運行的可用操作一樣,該相同的幫助機制也可以針對那些列出的特定命令中的任何一個運行[語法為jcmd <pid> <command_name> help (或使用進程名稱代替pid)],盡管我無法在Windows計算機上使其正常工作。
下圖顯示了針對該JVM進程實際運行該命令,而不是簡單地尋求幫助。
在緊接上方的兩個屏幕快照中,我針對pid(而不是進程名稱)運行jcmd ,只是為了表明它既可用于進程ID也可用于名稱。 下一個屏幕快照顯示了對JVM進程執行jcmd以從JVM進程獲取VM標志和命令行選項(此JConsole進程實例的pid為3556)。
對支持的JVM進程運行jcmd的Thread.print命令可以輕松地查看目標JVM的線程。 以下輸出是通過對運行的JConsole進程運行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從正在運行的JVM進程中獲取類直方圖。 使用命令jcmd <pid> GC.class_histogram完成此操作。 接下來顯示其輸出的一小部分(這次JConsole進程的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 (編譯方法統計信息)和jstat -options (顯示選項)的用法 。
在演示過程中,Larsen需要將十進制數(pid?) 轉換為其十六進制表示形式,以便將其與另一個工具的輸出進行比較。 他使用了方便的printf '%x\n' <pid>命令來獲取printf '%x\n' <pid>的十六進制表示形式。
Larsen演示了如何使用VisualVM比較兩個堆轉儲并瀏覽一個堆轉儲 。 他還演示了VisualVM Profiler 。
Larsen從先前介紹的旨在運行JVM的工具轉變為可用于分析JVM核心文件的工具。 他返回jstack分析核心文件的內容。
Larsen談到了通過JMX以及jconsole和jvisualvm類的工具遠程訪問JVM信息。 他演示了jcmd也可以用于啟動JMX jcmd : ManagementServer.start “帶有大量參數”。 Larsen認為,如果今天實現,VisualVM和JConsole將使用ManagementServer.start而不是Attach API。
jstat還可以通過使用jstatd遠程連接到守護程序。 沒有使用jstatd加密或身份驗證。
jps和jcmd使用“每個JVM的知名文件”查找系統上正在運行的文件:/ hsperfdata_ <user> / <pod>此文件在JVM啟動時創建,在JVM關閉時刪除。 未使用的先前文件會在啟動時被刪除,因此jps和jcmd作為Java程序本身會清除這些舊文件。
Attach API “允許發送“命令”以在JVM中執行”,但僅適用于本地計算機以及當前/相同用戶。 這就是jcmd和jstack用途。 然后,Larsen繼續說明了將Attach API用于Linux / BSD / Solaris(使用臨時文件創建)與Windows(使用代碼注入)的不同機制。 我在Groovy,JMX和Attach API中使用了Attach API 。
診斷命令是“ JVM內部的幫助程序”,可產生“文本輸出”。 可以通過jcmd實用程序(很快通過JMX)執行它們。 他們每個人都有一個自我描述的工具: jcmd PerfCounter.print可以查看原始內容。
Larsen顯示了一張比較“與JVM通信”方法的信息表: attach , jvmstat , JMX , jstatd和Serviceability Agent (SA)。 SA“應被用作最后的手段(通常用于掛起的JVM)”,并使用“調試器讀取信息”。
Larsen轉而談論未來的工具。 他從Java Flight Recorder的介紹開始了演示的這一部分。 Java Flight Recorder是“ JVM內置的探查器和跟蹤器”,具有“低開銷”并且“始終處于打開狀態”。 其他即將推出的工具包括Java Mission Control (“圖形工具,提供非常詳細的運行時監視詳細信息”),針對jcmd更多診斷命令(“出于各種原因最終替換jstack,jmap,jinfo”), JMX 2.0 (“我們正在了解的東西”)再次;它是在很久以前開始的),改進了JVM的日志記錄(JVM增強建議[JEP] 158 )和Java發現協議(為此即將推出JEP)。
一個問題是,是否可以像在JConsole中那樣在VisualVM中看到MBean。 正如我在上發表的文章 ,有一個VisualVM插件可以做到這一點。
盡管我對Oracle HotSpot JDK命令行工具感到有些滿意,但我并不熟悉jcmd并贊賞Larsen對它的介紹。 我也學到了其他一些東西。 我唯一的抱怨是Larsen的演講(尤其是演示)是如此Swift,內容如此豐富,我希望我能再次看到它。
可以在http://www.oracle.com/javaone/lad-en/session-presentations/corejava/22260-enok-1439100.pdf上找到相關的(但較舊的)具有相同內容的演示文稿。
參考: JavaOne 2012:在我們的JCG合作伙伴 Dustin Marx的Inspired by Actual Events博客上,在JVM上診斷您的應用程序 。
JVM 故障排除 2012-10-11
達斯汀·馬克思翻譯自: https://www.javacodegeeks.com/2012/10/javaone-2012-diagnosing-your.html
總結
以上是生活随笔為你收集整理的JavaOne 2012:在JVM上诊断应用程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用MongoDB进行事件流
- 下一篇: 数据库和Webapp安全