曾经 oracle 向我们提供了一套 jvm 管理与诊断问题的 “工具全家桶”: jps, jstack, jmap, jstat, jhat, jinfo 等等, 我们针对不同的情景使用不同的工具, 解决特定的问题;
现在, oracle 在 jdk7 之后又为我们带来了一个全能的工具 jcmd; 它最重要的功能是启动 java flight recorder, 不过 oracle 在设计该命令的时候, “不小心” 为它附加上了一些其他功能, 从而将原本平静的水面搅起了波澜;
jcmd 工具的定位
jcmd 是 jdk7 之后新增的工具, 它是 java flight recorder 的唯一启动方式, 详细的内容请见 java flight recorder 的使用; 不过, oracle 顺手又为其附带了一些 “便捷” 小工具:
- 列举 jvm 进程 (对标 jps)
- dump 栈信息 (对标 jstack)
- dump 堆信息 (对标 jmap -dump)
- 统计类信息 (对标 jmap -histo)
- 获取系统信息 (对标 jinfo)
这样一下子就有意思了, jcmd 似乎有了想要取代其他命令的野心; 下面来具体介绍一下 jcmd 都能顺手做些什么事情;
jps 类似功能
jcmd 命令不带任何选项或者使用 -l 选项, 都可以打印当前用户下运行的虚拟机进程;1
2
3
4# jps
sudo -u xxx jps -l
# jcmd
sudo -u xxx jcmd [-l]
查看 jcmd 对指定虚拟机能做的事情
jcmd 确实神通广大, 但是再厉害的大夫也得病人配合工作才行, 比如在低版本 jre 上跑的程序肯定无法使用 flight recorder 抓 dump;
当使用 jcmd 拿到了目标 vmid 后, 使用如下命令可以查看 jcmd 对目标 jvm 能够使用的功能:1
sudo -u xxx jcmd {vmid} help
输出可以使用的功能列举如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35# flight recorder 相关功能
JFR.stop
JFR.start
JFR.dump
JFR.check
# jmx 相关功能
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
# jstack 相关功能
Thread.print
# jmap 相关功能
GC.class_stats
GC.class_histogram
GC.heap_dump
# jinfo 相关功能
VM.flags
VM.system_properties
VM.command_line
VM.version
# gc 相关
GC.run_finalization # System.runFinalization()
GC.run # System.gc()
GC.rotate_log # 切割 gc log
# 其他
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
VM.uptime
jstack 类似功能
1 | sudo -u xxx jcmd {vmid} Thread.print |
以上命令输出的内容与以下使用 jstack 命令的输出一致:1
sudo -u xxx jstack -l {vmid}
jmap 类似功能
与 jmap 相关的功能主要是以下四类:
(1) 堆区对象的总体统计1
2# jmap 的实现
sudo -u xxx jmap -heap {vmid}
jcmd 没有提供与 jmap -heap 类似的功能;
(2) 堆区对象的详细直方图统计1
2
3
4# jcmd 的实现
sudo -u xxx jcmd {vmid} GC.class_histogram
# jmap 的实现
sudo -u xxx jmap -histo[:live] {vmid}
(3) metaspace 的信息统计1
2
3
4# jcmd 的实现
sudo -u xxx jcmd {vmid} GC.class_stats
# jmap 的实现
sudo -u xxx jmap -clstats {vmid}
虽然都是关于 jdk8 metaspace 的信息统计, 不过 jcmd GC.class_stats 与 jmap -clstats 的输出内容没什么关联;
另外, 使用 jcmd GC.class_stats 功能, 需要开启 jvm 选项 UnlockDiagnosticVMOptions
;
(4) 堆区对象的 dump1
2
3
4# jcmd 的实现
sudo -u xxx jcmd {vmid} GC.heap_dump {file_path}
# jmap 的实现
sudo -u xxx jmap -dump[:live],format=b,file={file_path} {vmid}
jinfo 类似功能
与 jinfo 相关的功能主要是以下两类:
(1) 打印 jvm 的系统信息, 包括系统参数, 版本等1
2
3
4
5# jcmd 的实现
sudo -u xxx jcmd {vmid} VM.system_properties
sudo -u xxx jcmd {vmid} VM.version
# jmap 的实现
sudo -u xxx jinfo -sysprops {vmid}
(2) 打印 jvm 的选项1
2
3
4# jcmd 的实现
sudo -u xxx jcmd {vmid} VM.command_line
# jmap 的实现
sudo -u xxx jinfo -flags {vmid}
(3) 修改 jvm 的选项1
2
3
4
5
6# jcmd 的部分实现
sudo -u xxx jcmd {vmid} VM.unlock_commercial_features
sudo -u xxx jcmd {vmid} VM.check_commercial_features
# jmap 的实现
sudo -u xxx jinfo -flag [+|-]{option_name} {vmid}
sudo -u xxx jinfo -flag {option_name}={value} {vmid}
关于修改 jvm 选项, 只能说 jcmd 几乎是没有相关的功能, 其只能操控与 flight recorder 配套的 UnlockCommercialFeatures
选项而已;
jcmd 使用总结
往不好听的讲, 除了 java flight recorder 之外, jcmd 其余的功能只能说是 “鸡肋”: 只有 jps, jstack 可以算完全覆盖了其相关功能, jmap 勉强可以算覆盖了其相关功能;
除此之外, jinfo 的部分功能没有实现, jstat 的所有功能都没有实现; 而且 jcmd 的选项名字一般都比较长, 不容易记住, 必须依赖 jcmd {vmid} help
打印相关内容, 给使用带来了不便;
总体来说, 除了 java flight recorder 必须要使用 jcmd 之外, 其余的功能暂时还是建议使用传统的工具来解决问题; jcmd 的野心还得继续培养, 等以后 oracle 发布新版本的时候再继续观察吧;