1.为什么需要JDK原生命令
在开发或测试环境中,我们可以通过可视化工具进行JVM的监控以及分析。但是往往在线上环境,因为安全以及性能,或者可视化工具部分功能不支持等原因,无法使用可视化工具进行JVM的监控以及分析。这时候JDK原生命令就可以派上用场了
2.JDK原生命令概述
JDK原生命令都是通过%JAVA_HOME%/lib/tools.jar包里面的Java方法来实现的,所以如果你想自己打造一个属于自己的JVM监控系统,那在Java程序内部调用该jar包的方法即可实现。
原生命令主要包括:jps、jinfo、jstat、jstack、jmap、jhat等命令,提供了查看虚拟机程序运行日志、异常堆栈信息、GC日志记录、线程快照文件、堆内存快照文件等相关功能
官方文档:JDK工具参考文档。同时可通过 ${命令} -help的形式获取其主要用法
3.jps(进程查看)
主要作用
jps的主要作用是用来查看机器上运行的Java进程,类似于Linux系统的ps -ef | grep java命令。jps工具也支持查看其他机器的Java进程,命令格式如下:
命令格式
主要参数
其中[options]主要有-q、-m、-l、-v、-V几个选项:
- jps -q:查看机器所有运行的Java进程,但只显示进程号(lvmid)。
- jps -m:~,只显示传递给main方法的参数。
- jps -l:~,只显示运行程序主类的包名,或者运行程序jar包的完整路径。
- jps -v:~,单独显示JVM启动时,显式指定的参数。
- jps -V:~,显示主类名或者jar包名。
其中[hostid]是用来连接其他机器查看Java进程的远程ID。
常用参数
4.jinfo(配置查看)
主要作用
主要用于实时查看JVM的运行参数,也可以在运行时动态的调整一些参数
命令格式
主要参数
其中[option1]可选项如下:
:第一个参数不写,默认输出JVM的全部参数和系统属性。 - -flag
:输出与指定名称 对应的所有参数,以及参数值。 - -flag [+|-]
:开启或者关闭与指定名称 对应的参数。 - -flag
= :设置与指定名称 对应参数的值。 - -flags:输出JVM全部的参数。
- -sysprops:输出JVM全部的系统属性。
其中[option2]可选项如下:
:对应的JVM进程ID(必需参数),指定一个jinfo要操作的Java进程。 - executable <core:输出打印堆栈跟踪的核心文件。
[server-id@]
:远程操作的地址。 [option]:监控参数选项。
- -t:在输出结果中加上Timestamp列,显示系统运行的时间。
- -h:可以在周期性数据输出的时候,指定间隔多少行数据后输出一次表头。
- vmid:Virtual Machine ID虚拟ID,也就是指定一个要监控的Java进程ID。
- interval:每次执行的间隔时间,默认单位为ms。
- count:用于指定输出多少条数据,默认情况下会一直输出。
执行命令jstat -option后,可以看到存在很多选项,如下:
- -class:输出类加载ClassLoad相关的信息。
- -compiler:显示与JIT即时编译相关的信息。
- -gc:显示与GC相关的信息。
- -gccapacity:显示每个分代空间的容量以及使用情况。
- -gcmetacapacity:输出元数据空间相关的信息。
- -gcnew:显示新生代空间相关的信息。
- -gcnewcapacity:显示新生代空间的容量大小以及使用情况。
- -gcold:输出年老代空间的信息。
- -gcoldcapacity:输出年老代空间的容量大小以及使用情况。
- -gcutil:显示垃圾回收信息。
- -gccause:和-gcutil功能相同,但是会额外输出最后一次或本次GC的诱因。
-printcompilation:输出JIT即时编译的方法信息。
常用参数
jstat -gc -t -h30 106368 2s 100
-gc:监控GC的状态
- -t:显示系统运行的时间
- -h30:间隔30行数据,输出一次表头
- 9895:Java进程ID
- 1s:时间间隔
- 300:本次输出的数据行数
字段 | 含义 |
---|---|
Timestamp | 系统运行的时间 |
S0C | 第一个Survivor区的总容量大小 |
S1C | 第二个Survivor区的总容量大小 |
S0U | 第一个Survivor区的已使用大小 |
S1U | 第二个Survivor区的已使用大小 |
EC | Eden区的总容量大小 |
EU | Eden区的已使用大小 |
OC | Old区的总容量大小 |
OU | Old区的已使用大小 |
MC | Metaspace区的总容量大小 |
MU | Metaspace区的已使用大小 |
CCSC | CompressedClassSpace空间的总大小 |
CCSU | CompressedClassSpace空间的已用大小 |
YGC | 从程序启动到采样时,期间发生的新生代GC次数 |
YGCT | 从程序启动到采样时,期间新生代GC总耗时 |
FGC | 从程序启动到采样时,期间发生的年老代GC次数 |
FGCT | 从程序启动到采样时,期间年老代GC总耗时 |
GCT | 从程序启动到采样时,程序发生GC的总次数 |
其他options示例
其他options参数说明
字段 | 含义 |
---|---|
S0 | 第一个Survivor区的使用率(S0U/S0C) |
S1 | 第二个Survivor区的使用率(S1U/S1C) |
E | Eden区的使用率(EU/EC) |
O | Old区的使用率(OU/OC) |
M | Metaspace区的使用率(MU/MC) |
CCS | CompressedClassSpace区的使用率(CCSU/CCSC) |
NGCMN | 新生代空间初始容量 |
NGCMX | 新生代空间最大容量 |
S0CMN | 第一个Survivor区的初始容量 |
S0CMX | 第一个Survivor区的最大容量 |
S1CMN | 第二个Survivor区的初始容量 |
S1CMX | 第二个Survivor区的最大容量 |
OGCMN | 年老代空间初始容量 |
OGCMX | 年老代空间最大容量 |
MCMN | 元数据空间初始容量 |
MCMX | 元数据空间最大容量 |
CCSMN | 类压缩空间初始容量 |
CCSMX | 类压缩空间最大容量 |
TT | 对象晋升的最小年龄阈值 |
MTT | 对象晋升的最大年龄阈值 |
DSS | 期望的Survivor区总大小 |
Class加载
字段 | 含义 |
---|---|
Loaded | JVM已经装载的类数量 |
Bytes | 已装载的类占用字节数大小 |
Unloaded | 已经卸载的类数量 |
Bytes | 已卸载的类占用字节数大小 |
Time | 卸载和装载类共耗时 |
JIT即时编译
字段 | 含义 |
---|---|
Compiled | 编译任务执行的总次数 |
Failed | 编译任务执行失败的次数 |
Invalid | 编译任务执行失效的次数 |
Bytes | 已卸载的类占用字节数大小 |
Time(options=) | 所有编译任务的总耗时 |
FailedType | 最后一个编译失败的任务类型 |
FailedMethod | 最后一个编译失败的任务所在的类及方法 |
6.jmap(内存查看(主要是堆区))
主要作用
jmap是一个多功能的工具,主要是用于查看堆空间的使用情况,通常会配合jhat工具一起使用,它可以用于生成Java堆的Dump文件。但除此之外,也可以查看finalize队列、元数据空间的详细信息,Java堆中对象统计信息,如每个分区的使用率、当前装配的GC收集器等。
命令格式
主要参数
其中[option1]可选项有:
- [no option]:查看进程的内存映像信息,与Solaris pmap类似。
- -heap:显示Java堆空间的详细信息。
- -histo[:live]:显示Java堆中对象的统计信息。
- -clstats:显示类加载相关的信息。
- -finalizerinfo:显示F-Queue队列中等待Finalizer线程执行finalizer方法的对象。
- -dump:
:生成堆转储快照。 - -F:当正常情况下-dump和-histo执行失效时,前面加-F可以强制执行。
- -help:显示帮助信息。
- -J
:指定传递给运行jmap的JVM参数。
其中[option2]与jinfo工具的相差无几,可选项如下:
:对应的JVM进程ID(必需参数),指定一个jinfo要操作的Java进程。 - executable <core:输出打印堆栈跟踪的核心文件。
[server-id@]
:远程操作的地址。 - server-id:远程debug服务的进程ID;
- remote server IP/hostname:远程debug服务的主机名 或 IP地址;
常用参数
查看堆区信息
jmap -heap
如图可以直观的看出当前堆空间,新生代(Eden区,from区,to区)和老年代总内存,使用内存,空闲内存,以及内存使用率等信息堆区文件转储
jmap -dump:live,format=b,file=Dump.phrof
如图,jmap命令可进行堆区文件的转储(dump)操作。后续可通过jhat或将文件复制到本地进行可视化分析。
一般线上机器都不开通远程端口,所以可以通过git、服务器中转再xftp拉取、挂到nginx等方式将线上服务器的堆转储文件拉取到本地
堆转储文件一般都比较大,所以记得拉取到本地后把服务器上的文件删除
例如使用VisualVM分析堆转储文件,如图:
如上图所示,可清晰的获取堆区对象总数,总字节数,GCRoot数等信息,同时可获取当前堆区占用内存最大的对象排名。便于分析内存溢出或内存泄漏问题7.jhat(堆内存文件分析)
主要作用
这个命令比较鸡肋
jhat工具一般配合jmap工具使用,主要用于分析jmap工具导出的Dump文件,其中也内嵌了一个微型的HTTP/HTML服务器,所以当jhat工具分析完Dump文件后,可以支持在浏览器中查看分析结果。(http://localhost:7000)
不过在线上环境中一般不会直接使用jhat工具对Dump文件进行解析,因为jhat解析Dump文件,尤其是大体积的Dump时,是一个非常耗时且占用硬件资源的过程。所以为了防止占用服务器过多的资源,通常都会将Dump文件copy到其他机器或本地中分析。
不过话说回来,到了本地一般也不会使用jhat,因为分析之后生成的结果通过浏览器观察时很难看,一般都会选择VisualVM、MAT(Eclipse Memory Analyzer)、IBM HeapAnalyzer、Jprofile等工具。命令格式/主要参数/常用参数
参考:点击这里8.jstack(线程查看)
主要作用
jstack工具主要用于捕捉JVM当前时刻的线程快照,线程快照是JVM中每条线程正在执行的方法堆栈集合。在线上情况时,生成线程快照文件可以用于定位线程出现长时间停顿的原因,如线程死锁、死循环、请求外部资源无响应等等原因导致的线程停顿。
当线程出现停顿时,可以通过jstack工具生成线程快照,从快照信息中能查看到Java程序内部每条线程的调用堆栈情况,从调用堆栈信息中就可以清晰明了的看出:发生停顿的线程目前在干什么,在等待什么资源等。
同时,当Java程序崩溃时,如果配置好了参数,生成了core文件,咱们也可以通过jstack工具从core文件中提取Java虚拟机栈相关的信息,从而进一步定位程序崩溃的原因。命令格式
jstack [option1] [option2]主要参数
其中[option1]可选项为:
-l:除开显示堆栈信息外,额外输出关于锁相关的附加信息(用于排查死锁问题)。
- -m:如果线程调用到本地方法栈中的本地方法,也显示C/C++的堆栈信息。
其中[option2]可选项如下:
:对应的JVM进程ID(必需参数),指定一个jinfo要操作的Java进程。 - executable <core:输出打印堆栈跟踪的核心文件。
[server-id@]
:远程操作的地址。 runnable,线程处于执行中
- deadlock,死锁(重点关注)
- blocked,线程被阻塞 (重点关注)
- Parked,停止
- locked,对象加锁
- waiting,线程正在等待
- waiting to lock 等待上锁
- Object.wait(),对象等待中
- waiting for monitor entry 等待获取监视器(重点关注)
- Waiting on condition,等待资源(重点关注),最常见的情况是线程在等待网络的读写
9.总结
通过以上的命令说明,可以了解到JDK原生虚拟机分析命令(工具)的用法。总结如下
虚拟机指令 | 常用指令格式 | 作用 |
---|---|---|
jps | jps -l | 查看java进程 |
jinfo | jinfo |
查看当前进程系统/虚拟机配置信息 |
jstat | jstat -gc -t -h30 |
查看当前进程虚拟机各种统计信息(堆区内存、类加载等) |
jmap | jmap -heap jmap -dump:live,format=b,file=test.phrof |
查看堆区详细信息/堆区文件转储(dump) |
jhat | 没用过 | 分析堆区文件(鸡肋命令,因为性能问题基本不用) |
jstack | jstack -l jstack -l |
查看线程详细信息/线程文件转储(dump) |
一般来说的顺序
- jps -l 获取进程信息
- jmap -heap pid 获取当前堆区详细信息
- jstat -gc -t -h30 pid 3s 300 获取垃圾回收信息
- jmap -dump:live,format=b,file=test.phrof pid 将当前堆区信息转储(dump)文件
- jstack -l pid > test.tdump 将当前线程信息转储(dump)文件
- jinfo -flags pid 查看当前应用程序(进程)虚拟机启动参数并进行修改