jcmd is one of those neat tools that only a few people seem to know about. It is a command line tool that is shipped with each Oracle JDK installation and provides basic information about a running Java process, which is practical for unobtrusively inspecting a running production instance.
How to Use jcmd
jcmd we need to specify the process id of a running Java process. When
jcmd is invoked without any arguments, it prints a list of all running Java processes:
daniel@thebe:~ $ jcmd 10322 name.mitterdorfer.demos.jcmd.Main 10307 org.gradle.launcher.GradleMain run 10325 sun.tools.jcmd.JCmd
Next, we can list the available commands for a process by issuing
jcmd <<PID>> help:
daniel@thebe:~ $ jcmd 10322 help 10322: The following commands are available: JFR.stop JFR.start JFR.dump JFR.check VM.native_memory VM.check_commercial_features VM.unlock_commercial_features ManagementAgent.stop ManagementAgent.start_local ManagementAgent.start Thread.print GC.class_stats GC.class_histogram GC.heap_dump GC.run_finalization GC.run VM.uptime VM.flags VM.system_properties VM.command_line VM.version help For more information about a specific command use 'help <command>'.
The supported options vary from process to process (e.g. due to VM options). For this example, there are four categories of commands:
- JFR: These are commands that control Java Flight Recorder which is really great for monitoring an application and deserves its own post (or even a series of posts). Note that while you are allowed to use Java Flight Recorder during development you need to obtain a separate license from Oracle to use it on production systems 1.
- VM: Basic information about the running JVM instance
- GC: Basic information about GC behavior and commands to force a GC or finalization
- Others: help, options to control the Java management agent and taking thread dumps
There is also one option that is not listed here, called "PerfCounter.print". It prints JVM-internal performance counters which contain lots of details on the behavior of components like the classloader, the JIT, the GC and a few others. To get started, the commands listed above should do but if you are really curios just try it.
A Practical Example
Suppose an application takes ages to start on a production system although it worked fine in development. To determine what's going on, we can take a thread dump:
daniel@thebe:~ $ jcmd 10378 Thread.print 10378: 2015-04-20 11:21:04 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.0-b70 mixed mode): "Attach Listener" #10 daemon prio=9 os_prio=31 tid=0x00007fa7ef008000 nid=0x5b03 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE [...] "main" #1 prio=5 os_prio=31 tid=0x00007fa7ee800000 nid=0x1903 waiting on condition [0x0000000102dbf000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at name.mitterdorfer.demos.jcmd.Main.main(Main.java:8) "VM Thread" os_prio=31 tid=0x00007fa7ec857800 nid=0x3503 runnable "GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007fa7ee80d000 nid=0x2503 runnable [...] "GC task thread#7 (ParallelGC)" os_prio=31 tid=0x00007fa7ec80b800 nid=0x3303 runnable "VM Periodic Task Thread" os_prio=31 tid=0x00007fa7ed801800 nid=0x5903 waiting on condition JNI global references: 7
Can you see what's going on? The main thread is in TIMED_WAITING state which means it is sleeping. Although this is not a very realistic example, such a thread dump once helped me find a weird startup issue in production: The logging framework of an application was misconfigured to log everything on DEBUG level but without specifying one of our application's file appenders. Therefore, no log statement ever reached the application's log files but it seemed that the application was not doing anything for minutes. I took a few thread dumps which revealed the problem quickly: Most thread dumps revealed that a debug statement was issued deep in library code. We corrected the log configuration and the application started smoothly again.
jcmd supports basic inspections in limited environments such as a production machine. Sure, there are more sophisticated tools like jconsole, Java Mission Control or third-party tools like AppDynamics. However, for a quick glimpse
jcmd is quite handy as it comes with every JDK installation and requires no graphical interface.