そろそろいい加減に、jpsから各種のJDK付属のツールから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を使っていきますが。
環境
コマンドを確認した環境は、こちら。
$ 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=
その他
全部を書いているわけではないですが、またまとめたいものがあったら、順次追記していきます。