CLOVER🍀

That was when it all began.

jcmdメモ

そろそろいい加減に、jpsから各種のJDK付属のツールからjcmdに慣れていこうかなと思い、個人的にメモとしてまとめることにしました。

既存のコマンドと、対比させる形で書いていきます。

参考

参考にしたのは、このあたり。

jcmdユーティリティ

jcmd

jcmdを使ったプロセスの指定方法は、これだけあるんですね。

プロセス識別子(pid)またはメイン・クラス(main-class)を1番目の引数として指定すると、jcmdは診断コマンド要求を、指定した識別子を持つJavaプロセスまたは指定したメインクラス名を持つすべてのJavaプロセスに送信します。また、プロセス識別子として0を指定すると、診断コマンド要求を使用可能なすべてのJavaプロセスに送信できます。診断コマンド要求として次のいずれかを使用します。

https://docs.oracle.com/javase/jp/8/docs/technotes/tools/windows/jcmd.html

ここでは、主にPIDを使っていきますが。

jcmd と既存ツールの対応 - sugarlife's blog

jcmdを試す - abcdefg.....

Java7からのjcmdのススメ(ThreadDump/HeapDump他)

環境

コマンドを確認した環境は、こちら。

$ java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)

確認用のプログラム

今回のサンプルとして、こんなのを用意。
example/App.java

package example;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

public class App {
    public static void main(String... args) {
        String message = args[0];
        
        Thread t = new Thread(() -> {
                while (true) {
                    System.out.println(LocalDateTime.now() + " Hello " + message);

                    try {
                        TimeUnit.SECONDS.sleep(1L);
                    } catch (InterruptedException e) {
                        // ignore
                    }
                }
            }, "my-thread");

        t.start();

        try {
            t.join();
        } catch (InterruptedException e) {
            // ignore
        }
    }
}

実行コマンドは、こちら。

$ java -Xmx512M -Dmy.property=foo -cp classes example.App World
2018-05-20T22:23:18.769 Hello World
2018-05-20T22:23:19.771 Hello World
2018-05-20T22:23:20.772 Hello World

では、順次見ていってみます。

ヘルプの標示方法

シンプルに、「-h」オプション。

$ jcmd -h
Usage: jcmd <pid | main class> <command ...|PerfCounter.print|-f file>
   or: jcmd -l                                                    
   or: jcmd -h                                                    
                                                                  
  command must be a valid jcmd command for the selected jvm.      
  Use the command "help" to see which commands are available.   
  If the pid is 0, commands will be sent to all Java processes.   
  The main class argument will be used to match (either partially 
  or fully) the class used to start Java.                         
  If no options are given, lists Java processes (same as -p).     
                                                                  
  PerfCounter.print display the counters exposed by this process  
  -f  read and execute commands from the file                     
  -l  list JVM processes on the local machine                     
  -h  this help

PID(もしくはmain class)を指定するタイプのものは、まずは使えるコマンドを「[PID] help」で標示可能。

$ jcmd [PID] help 
18586:
The following commands are available:
VM.native_memory
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
GC.rotate_log
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>'.

さらに、PIDを指定しつつ「help」とコマンドを入力すると、コマンドごとに詳しい内容が標示されます。

$ jcmd [PID] help Thread.print
18586:
Thread.print
Print all threads with stacktraces.

Impact: Medium: Depends on the number of threads.

Permission: java.lang.management.ManagementPermission(monitor)

Syntax : Thread.print [options]

Options: (options must be specified using the <key> or <key>=<value> syntax)
	-l : [optional] print java.util.concurrent locks (BOOLEAN, false)

Javaプロセス一覧(jps相当)

「jps -lm」と同じであれば、以下になります。

$ jcmd

出力例。

18660 sun.tools.jcmd.JCmd
18586 example.App World

または

$ jcmd -l

出力例。

18680 sun.tools.jcmd.JCmd -l
18586 example.App World

「-l」の有無で、出力内容に差はありません。

jpsでの「-v」相当の情報は、これだと取れません。

起動引数を取得したい場合は、こちら。

$ jcmd [PID] VM.command_line

出力例。

18586:
VM Arguments:
jvm_args: -Xmx512M -Dmy.property=foo 
java_command: example.App World
java_class_path (initial): classes
Launcher Type: SUN_STANDARD

「jps -mlv」に比べると、ちょっと面倒…。

パフォーマンスカウンタ(jstat相当)

$ jcmd [PID] PerfCounter.print

出力例。

18586:
java.ci.totalTime=266593286
java.cls.loadedClasses=697
java.cls.sharedLoadedClasses=0
java.cls.sharedUnloadedClasses=0
java.cls.unloadedClasses=8
java.property.java.class.path="classes"
java.property.java.endorsed.dirs="/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/endorsed"
java.property.java.ext.dirs="/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext:/usr/java/packages/lib/ext"
java.property.java.home="/usr/lib/jvm/java-8-openjdk-amd64/jre"
java.property.java.library.path="/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib"
java.property.java.version="1.8.0_171"
java.property.java.vm.info="mixed mode"
java.property.java.vm.name="OpenJDK 64-Bit Server VM"
java.property.java.vm.specification.name="Java Virtual Machine Specification"
java.property.java.vm.specification.vendor="Oracle Corporation"
java.property.java.vm.specification.version="1.8"
java.property.java.vm.vendor="Oracle Corporation"
java.property.java.vm.version="25.171-b11"
java.rt.vmArgs="-Xmx512M -Dmy.property=foo"
java.rt.vmFlags=""
java.threads.daemon=4
java.threads.live=6
java.threads.livePeak=6
java.threads.started=6

〜省略〜

sun.gc.generation.0.capacity=50331648
sun.gc.generation.0.maxCapacity=178782208
sun.gc.generation.0.minCapacity=50331648
sun.gc.generation.0.name="new"
sun.gc.generation.0.space.0.capacity=37748736
sun.gc.generation.0.space.0.initCapacity=0
sun.gc.generation.0.space.0.maxCapacity=177733632
sun.gc.generation.0.space.0.name="eden"
sun.gc.generation.0.space.0.used=754992
sun.gc.generation.0.space.1.capacity=6291456
sun.gc.generation.0.space.1.initCapacity=0
sun.gc.generation.0.space.1.maxCapacity=59244544
sun.gc.generation.0.space.1.name="s0"
sun.gc.generation.0.space.1.used=0
sun.gc.generation.0.space.2.capacity=6291456
sun.gc.generation.0.space.2.initCapacity=0
sun.gc.generation.0.space.2.maxCapacity=59244544
sun.gc.generation.0.space.2.name="s1"
sun.gc.generation.0.space.2.used=0
sun.gc.generation.0.spaces=3
sun.gc.generation.1.capacity=38797312
sun.gc.generation.1.maxCapacity=358088704
sun.gc.generation.1.minCapacity=100663296
sun.gc.generation.1.name="old"
sun.gc.generation.1.space.0.capacity=38797312
sun.gc.generation.1.space.0.initCapacity=100663296
sun.gc.generation.1.space.0.maxCapacity=358088704
sun.gc.generation.1.space.0.name="old"
sun.gc.generation.1.space.0.used=869608
sun.gc.generation.1.spaces=1
sun.gc.lastCause="Heap Inspection Initiated GC"
sun.gc.metaspace.capacity=4980736
sun.gc.metaspace.maxCapacity=1082130432
sun.gc.metaspace.minCapacity=0
sun.gc.metaspace.used=4482840

〜省略〜

sun.rt.applicationTime=1793257092448
sun.rt.createVmBeginTime=1526823101812
sun.rt.createVmEndTime=1526823101858
sun.rt.internalVersion="OpenJDK 64-Bit Server VM (25.171-b11) for linux-amd64 JRE (1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11), built on Apr 27 2018 17:19:03 by "buildd" with gcc 5.4.0 20160609"
sun.rt.interruptedBeforeIO=0
sun.rt.interruptedDuringIO=0
sun.rt.javaCommand="example.App World"
sun.rt.jvmCapabilities="1100000000000000000000000000000000000000000000000000000000000000"
sun.rt.jvmVersion=430637067
sun.rt.safepointSyncTime=1671970
sun.rt.safepointTime=1856685473
sun.rt.safepoints=21
sun.rt.threadInterruptSignaled=0
sun.rt.vmInitDoneTime=1526823101846
sun.threads.vmOperationTime=1853640557
sun.urlClassLoader.readClassBytesTime=1078438
sun.zip.zipFile.openTime=1672337
sun.zip.zipFiles=10

膨大な量が1回表示されて終了するので、厳密に「相当」とは言いづらい感じが。

スレッドダンプ(jstack相当)

$ jcmd [PID] Thread.print

出力例。

18586:
2018-05-20 22:32:44
Full thread dump OpenJDK 64-Bit Server VM (25.171-b11 mixed mode):

"Attach Listener" #11 daemon prio=9 os_prio=0 tid=0x00007f99b0001000 nid=0x4963 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"my-thread" #10 prio=5 os_prio=0 tid=0x00007f99f019f800 nid=0x48c0 waiting on condition [0x00007f99c51bc000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at example.App.lambda$main$0(App.java:15)
	at example.App$$Lambda$1/455659002.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f99f00ca000 nid=0x48ac runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007f99f00c7000 nid=0x48ab waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

〜省略〜

"VM Thread" os_prio=0 tid=0x00007f99f0080000 nid=0x48a4 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f99f001f800 nid=0x489c runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f99f0021800 nid=0x489d runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f99f0023000 nid=0x489e runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f99f0025000 nid=0x489f runnable 

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f99f0026800 nid=0x48a0 runnable 

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f99f0028800 nid=0x48a1 runnable 

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f99f002a000 nid=0x48a2 runnable 

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f99f002c000 nid=0x48a3 runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f99f00cc800 nid=0x48ad waiting on condition 

JNI global references: 320

「jstack -F」(強制出力)とか「jstack -m」(ネイティブC/C++フレームの情報)相当を実現する方法はないのかな?

ヒープダンプ(jmap -dump:live,format=b相当)

$ jcmd [PID] GC.heap_dump filename=[Heap Dump Filename]

出力例。

18586:
Heap dump file created

「-all」オプションをつけることで、非参照オブジェクトもダンプ可能。

Options: (options must be specified using the <key> or <key>=<value> syntax)
	-all : [optional] Dump all objects, including unreachable objects (BOOLEAN, false)

ヒープヒストグラム(jmap -histo:live相当)

$ jcmd [PID] GC.class_histogram

出力例。

18586:

 num     #instances         #bytes  class name
----------------------------------------------
   1:           795         223600  [B
   2:          2977         196800  [C
   3:           806          92176  java.lang.Class
   4:          2965          71160  java.lang.String
   5:          1493          47776  java.util.concurrent.ConcurrentHashMap$Node
   6:           870          41032  [Ljava.lang.Object;
   7:           273          13664  [I
   8:           194          10864  java.lang.invoke.MemberName
   9:            14          10528  [Ljava.util.concurrent.ConcurrentHashMap$Node;
  10:           288           9216  java.util.HashMap$Node

〜省略〜

 285:             1             16  sun.misc.Launcher
 286:             1             16  sun.misc.Launcher$Factory
 287:             1             16  sun.misc.Perf
 288:             1             16  sun.misc.Unsafe
 289:             1             16  sun.net.www.protocol.file.Handler
 290:             1             16  sun.reflect.ReflectionFactory
 291:             1             16  sun.util.calendar.Gregorian
Total         14808         869608

こちらも、「-all」を付与することで、非参照オブジェクトも表示可能です。

フラグの有効有無の確認(jinfo -flag相当)

$ jcmd [PID] VM.flags

出力例。

18586:
-XX:CICompilerCount=4 -XX:InitialHeapSize=150994944 -XX:MaxHeapSize=536870912 -XX:MaxNewSize=178782208 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=50331648 -XX:OldSize=100663296 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC

「-all」オプションを付与することで、全フラグの状態が出力されます。

$ jcmd [PID] VM.flags -all
Options: (options must be specified using the <key> or <key>=<value> syntax)
	-all : [optional] Print all flags supported by the VM (BOOLEAN, false)

出力例。

18586:
[Global flags]
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10                                  {product}
    uintx AdaptiveSizePausePolicy                   = 0                                   {product}
    uintx AdaptiveSizePolicyCollectionCostMargin    = 50                                  {product}
    uintx AdaptiveSizePolicyInitializingSteps       = 20                                  {product}
    uintx AdaptiveSizePolicyOutputInterval          = 0                                   {product}
    uintx AdaptiveSizePolicyWeight                  = 10                                  {product}
    uintx AdaptiveSizeThroughPutPolicy              = 0                                   {product}
    uintx AdaptiveTimeWeight                        = 25                                  {product}
     bool AdjustConcurrency                         = false                               {product}
     bool AggressiveOpts                            = false                               {product}
     intx AliasLevel                                = 3                                   {C2 product}
     bool AlignVector                               = true                                {C2 product}

〜省略〜

     bool UseXmmLoadAndClearUpper                   = true                                {ARCH product}
     bool UseXmmRegToRegMoveAll                     = true                                {ARCH product}
     bool VMThreadHintNoPreempt                     = false                               {product}
     intx VMThreadPriority                          = -1                                  {product}
     intx VMThreadStackSize                         = 1024                                {pd product}
     intx ValueMapInitialSize                       = 11                                  {C1 product}
     intx ValueMapMaxLoopSize                       = 8                                   {C1 product}
     intx ValueSearchLimit                          = 1000                                {C2 product}
     bool VerifyMergedCPBytecodes                   = true                                {product}
     bool VerifySharedSpaces                        = false                               {product}
     intx WorkAroundNPTLTimedWaitHang               = 1                                   {product}
    uintx YoungGenerationSizeIncrement              = 20                                  {product}
    uintx YoungGenerationSizeSupplement             = 80                                  {product}
    uintx YoungGenerationSizeSupplementDecay        = 8                                   {product}
    uintx YoungPLABSize                             = 4096                                {product}
     bool ZeroTLAB                                  = false                               {product}
     intx hashCode                                  = 5                                   {product}

まるで、「-XX:+PrintFlagsFinal」みたいですね。

システムプロパティ一覧(jinfo -sysprops相当)

$ jcmd [PID] VM.system_properties

出力例。

18586:
#Sun May 20 23:15:08 JST 2018
java.runtime.name=OpenJDK Runtime Environment
sun.boot.library.path=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64
java.vm.version=25.171-b11
java.vm.vendor=Oracle Corporation
java.vendor.url=http\://java.oracle.com/
my.property=foo
path.separator=\:
java.vm.name=OpenJDK 64-Bit Server VM
file.encoding.pkg=sun.io
user.country=JP
sun.java.launcher=SUN_STANDARD
sun.os.patch.level=unknown
java.vm.specification.name=Java Virtual Machine Specification

〜省略〜

java.home=/usr/lib/jvm/java-8-openjdk-amd64/jre
sun.arch.data.model=64
user.language=ja
java.specification.vendor=Oracle Corporation
awt.toolkit=sun.awt.X11.XToolkit
java.vm.info=mixed mode
java.version=1.8.0_171
java.ext.dirs=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext\:/usr/java/packages/lib/ext
sun.boot.class.path=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/resources.jar\:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar\:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/sunrsasign.jar\:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jsse.jar\:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jce.jar\:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/charsets.jar\:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jfr.jar\:/usr/lib/jvm/java-8-openjdk-amd64/jre/classes
java.vendor=Oracle Corporation
file.separator=/
java.vendor.url.bug=http\://bugreport.sun.com/bugreport/
sun.io.unicode.encoding=UnicodeLittle
sun.cpu.endian=little
sun.desktop=gnome
sun.cpu.isalist=

その他

全部を書いているわけではないですが、またまとめたいものがあったら、順次追記していきます。