jcmd使用简介

简单介绍

JDK1.7之后新增的一个命令,大型真香现场。 基本结合了jmap, jstat, jstack, jps, jinfo等常用命令,使用起来比较方便简单。

一个可以发送诊断命令给JVM的工具,对控制Java飞行记录器、故障排除、JVM诊断和java应用诊断比较有用。

PS:jcmd只能用在与正在运行的JVM实例的机器上,并且必须要有JVM启动时的用户权限。 即:jcmd不能用于远程诊断。

语法

jcmd [ -l | -h | -help ]
jcmd <pid|main-class> PerfCounter.print
jcmd <pid|main-class> -f filename
jcmd <pid|main-class> command [ arguments]

jcmd后可以跟pid,也可以跟主函数名称。这里需要注意的是,main-class并不是指打包的jar包里面的Main-Class所指的信息。而是指当前ps -ef | grep xxx得到的进程信息里面的关键字。

比如,以halo博客为例。

启动脚本如下为:

/opt/soft/jdk18/jdk1.8.0_101/bin/java -Xms512m -Xmx512m -XX:NativeMemoryTracking=summary -jar halo-1.2.0.jar

使用JD-JUI反编译halo的代码,查看MANIFEST.MF,发现Main-Class为:org.springframework.boot.loader.JarLauncher 如下图:

image-20200419185423499

当我们使用jcmd org.springframework.boot.loader.JarLauncher help命令的时候,发现提示找不到。如下图:

image-20200419185451333

但当我们使用jcmd halo help的时候,反而能得到具体的信息。如下图

image-20200419185551631

所以,main-class指的是java进程的关键字,能唯一找到java进程的关键字。

另外: jcmd 5121 helpjcmd halo help 的作用是一样的,如下图:(PS:5121为halo进程的pid)

image-20200419185612381

PS:

建议使用pid的方式,能更准确的调试需要的进程。

参数说明

jcmd [ -l | -h | -help ]

jcmdjcmd -l 等价于jps ,列出当前运行中的java进程。

jcmd -hjcmd -help 显示当前命令的帮助文档

jcmd <pid|main-class> PerfCounter.print

jcmd的一个特殊命令,可以打印目标进程上所有的性能计数器。

jcmd <pid|main-class> -f filename

从文件中读取命令,并在目标进程上执行。

一个命令一行,#表示注释。当读完所有行(命令)或者遇到stop关键字的时候,则停止读取,文件处理完成。

暂时没有实际使用到的场景,猜测的使用场景为,定期的去做jvm进程监测的时候,可以通过这种方式来批量处理。

jcmd <pid|main-class> command [ arguments]

这是比较常用的命令语法。

jcmd帮助命令

jcmd pid help 可以查看当前进程上可用的命令。如下图:

image-20200419192938509

针对每个命令,可以使用 jcmd pid help <command>的方式查看具体每个命令的帮助文档,如下图:

image-20200419193200103

几个实用的jcmd命令
命令说明替代命令
jcmd pid VM.version查看当前JVM的版本信息相当于:jinfo -sysprops
jcmd pid VM.system_properties查看当前进程JVM的属性信息相当于:jinfo -sysprops
jcmd pid VM.flags打印当前JVM参数信息,如果没有JVM参数,也会打印一些默认值,比如初始堆大小相当于jinfo -flags
jcmd pid VM.uptime打印系统运行的时间
jcmd pid GC.class_histogram
jcmp pid GC.class_histogram filename=histogram.histo
打印class的直方图相当于jmap -histo pid
jcmd pid GC.heap_dump filename=dump.bindump堆转储。注意:filename默认存储位置是当前java进程启动脚本所在目录。相当于jmap -dump:live,format=b,file=heap.bin pid
jcmd pid Thread.print打印堆栈信息相当于jstack pid
jcmd pid VM.command_line查看当前的JVM启动命令行信息相当于 jinfo -sysprops
jcmd pid GC.run_finalization对JVM执行System.runFinalization()函数
jcmd pid GC.run对JVM执行System.gc()函数。之前LinuxTop RES和JVM XMS关系文章里面提到的手动触发FullGC,也可以通过这种方式来触发
JFR

针对JVM飞行器记录的一些命令。关于飞行器记录,可以参考官网Java Fight Recorder

命令说明
jcmd pid JFR.start name=<name> duration=120s filename=<jfrfilename>启动JFR,eg: jcmd 5121 JFR.start name=jfrDemo duration=120s filename=jfrDemp.jfr
启动JFR录制,并在120s之后,将其保存到java进行启动目录下的jfrDemo.jfr文件中
注意:如果JFR.start 不跟filenameduration参数的话,则需要JFR.dump命令来停止记录并做转储。
jcmd pid JFR.dump name=<name> filename=<jfrfilename>执行dump,需要先执行JFR.start。filename必须以jfr结尾 eg: jcmd 5121 JFR.dump name=jfrDemo filename=jrfDemo.jfr
jcmd pid JFR.check检查当前正在运行的飞行器记录
jcmd pid JFR.stop停止飞行器记录,数据将会丢失

PS:

java飞行记录器需要解锁commercial features 才可以用。

使用jcmd pid VM.unlock_commercial_features 可以解锁。

JFR的使用例子:

[root@AY1312180952417614c9Z ~]# jcmd 5121 JFR.start name=jfrDemo duration=120s filename=jfrDemp.jfr
5121:
Java Flight Recorder not enabled.

Use VM.unlock_commercial_features to enable.
[root@AY1312180952417614c9Z ~]# jcmd 5121 VM.unlock_commercial_features
5121:
Commercial Features now unlocked.
[root@AY1312180952417614c9Z ~]# jcmd 5121 JFR.start name=jfrDemo duration=120s filename=jfrDemp.jfr
5121:
Started recording 1. The result will be written to:

/opt/web/blog/jfrDemp.jfr
[root@AY1312180952417614c9Z ~]# jcmd 5121 JFR.check
5121:
Recording: recording=1 name="jfrDemo" duration=2m filename="jfrDemp.jfr" compress=false (running)

[root@AY1312180952417614c9Z blog]# jcmd 5121 JFR.check
5121:
Recording: recording=1 name="jfrDemo" duration=2m filename="jfrDemp.jfr" compress=false (stopped)

JFR的文件需要使用jmc来查看。

关于JFR实操,osx下的jmc启动有问题,后面有机会的话,找个案例实际试验一下。

参考

Oracle JCMD官方文档

Oracle JFR介绍

JFR初探

Jcmd命令详解