javaone
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: 563 Larsen展示了如何使用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 [[I Larsen还演示了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