JVM-jstat
jmap -heap pid
jstat
jstat:虚拟机统计信息监视工具(JVM Statistics Monitoring Tool)
说明:监视虚拟机的各种运行状态:类装载、内存、垃圾收集等运行数据。只用于Java进程或Java应用
格式:jstat [option] PID [interval] [count]
$ jstat -gcutil
option:
-class 查看类装载的信息
-gc 查看java堆的状况
-gccapacity 查看堆中各个区域的最小容量和最大容量
-gcutil 查看堆中各个区域已使用空间占其总空间的百分比
-gccause 与-gcutil相同,另外还输出了:导致上一次GC的原因和当前GC的原因
-gcnew 查看堆中新生代的状况
-gcnewcapacity 查看堆中新生代的最小容量和最大容量
-gcold 查看堆中老年代的状况
-gcoldcapacity 查看堆中老年代的最小容量和最大容量
-gcpermcapacity 查看堆中永久代的最小容量和最大容量
-gcmetacapacity 查看元数据空间的当前大小、最大容量和最小容量(jdk1.8)
interval:表示查询的间隔时间,单位:毫秒
count: 表示查询的次数,如果interval和count都省略,则默认为只查询一次。
这是 class
例子
这条命令的意思是查看类加载器统计信息
1 | jstat -class -h3 -t pid 1000 8 |
参数
- -class监控类加载器统计信息,当然我们还可以监控垃圾收集堆统计信息(-gc)等信息。
- h3选项每三条信息加一个列标题(可选)
- -t选项是在在首列加一列距离jvm启动的时间戳(可选)
- 16468是jvm进程id(必须)
- 1000是每隔1000毫秒打印一条数据(可选,默认打印一条)
- 8是打印8条数据(可选,如果指定了间隔时间,将持续打印)
结果
- -class监控类加载器统计信息标题解释
- Timestamp 距离jvm启动的时间戳
- Loaded:已加载的类数。
- Bytes:加载的kB数。
- Unloaded:卸载的类数。
- Bytes:已卸载的Kbytes数。
- Time:执行类加载和卸载操作所花费的时间。
这是 gcutil
例子
1 |
|
查询结果标识:
通用:
SOC: S0区总共容量
S1C: S1区总共容量
S0U: S0区使用的量
S1U: S1区使用的量
EC: 伊甸园区总共容量
EU:伊甸园区使用的量
OC:老年代总共容量
OU:老年代使用的量
Minor GC(Young GC):
YGC: 进程从启动以来Minor GC的次数
YGCT:进程从启动以来Minor GC所花费的时间
Full GC:FGC表示次数,FGCT表示时间
FGC: 进程从启动以来Full GC的次数
FGCT:进程从启动以来Full GC所花费的时间
GCT: Minor GC和Full GC总共花费的时间
注:查看 JVM 是否回收垃圾频繁,主要根据 FGC 和 FGCT 来分析。上面的命令
$ jstat -gcutil 8842 2000 10 该命令对进程 8842 进行监控收集信息,每 2 秒收集一次,供收集 10 次。此时看 FGC
这一列,最新收集的信息排在最上面。用下一行的数字,减去上一行的数字,可得知每2秒内垃圾收集的次数(可换算成1秒的次数)
,若是回收垃圾频繁,则需要进一步分析原因。可能的原因是内存泄露、程序中有创建大对象的代码、相关配置设置的阈值较小。再进一步查找问题,可以打印出具体的堆栈信息,通过堆栈定位到具体的代码进行分析。
相关命令解析:
jstat -gc
jstat -gcutil
jstat -gccause
新生代(Young)中的Eden区:E
E: Eden区已使用的空间占其总空间的百分比
EC:Eden区的容量(Eden Capacity)
EU:Eden区已使用的空间(Eden Use)
新生代(Young)中的Survivor区:S0 S1
老年代(Old):O
永久代(Permanent):P
jdk8中:
元数据空间(Metaspace):M
元数据空间中的压缩类空间(Compressed Class Space):CCS
说明:
1>jdk8中已经没有永久代了,取而代之的是元空间,元空间占用的是本地内存,不占用虚拟机的内存。
2>Metaspace由Klass Metaspace和NoKlass Metaspace两部分组成。
3>M表示Metaspace已使用的百分比,CCS表示Klass Metaspace已使用的百分比(CCS=CCSU/CCSC)。
4>M的值达到了90%以上,不一定能说明metaspace已经用了很多了,因为内存是慢慢commit的,所以我们的分母是慢慢变大的,不过当我们commit到一定量的时候就不会再增长了。
5>根据MC,MU,CCSC,CCSU来判断metaspace的状态更靠谱。(注:可以在jstat -gc 中看到MU)
注:S0/S0C/S0U、S1/S1C/S1U、O/OC/OU、P/PC/PU、M/MC/MU、CCS/CCSC/CCSU 与 E/EC/EU类似
LGCC:最后一次GC发生的原因
GCC: 当前GC发生的原因
jstat -gccapacity
NGCMN:新生代的最小(初始化)容量
NGCMX:新生代的最大容量
NGC: 新生代当前的容量
ECMX: 新生代中Eden区的最大容量
S0CMX、S1CMX:新生代中Survivor区的最大容量
OGCMN:老年代的最小(初始化)容量
OGCMX:老年代的最大容量
OGC: 老年代当前的容量
PGCMN:永久代的最小(初始化)容量
PGCMX:永久代的最大容量
PGC: 永久代当前的容量
jdk8中:
MCMN: 元数据空间最小容量
MCMX: 元数据空间最大容量
MC: 当前元数据空间的大小
CCSMN: 压缩类空间CCS(即:Klass Metaspace)的最小容量
CCSMX: 压缩类空间CCS(即:Klass Metaspace)的最大容量
CCSC: 当前压缩类空间CCS(即:Klass Metaspace)的大小
jstat -gcnew
TT: 老年化阈值。被移动到老年代之前,在新生代空存活的次数
MTT:最大老年化阈值。
DSS:幸存者区所需空间大小
注意:单位是都是KB
系统异常排查的定位方法
定位相关进程的堆栈信息
查看进程的信息
$ ps -mp
该命令是查看某个进程下线程的具体信息,sort参数根据线程占用的cpu比例进行排序
$ top -Hp
查看某个进程下面线程的摘要信息,包括线程ID,cpu占用,内存占用,虚拟内存,运行时间等
以上两个命令,主要查找进程里面消耗CPU最高的线程
- 将占用cpu资源最高的线程,转换为16进制
$ printf “%xn” <线程ID>
- 打印线程(十六进制)的堆栈信息
$ jstack
另一种比较简单粗暴的方法,查看进程的堆栈情况
$ jstack
先通过步骤 1 ,查找到消耗CPU最高的进程,将该进程的堆栈信息打印出来,输入到jstack.out 文件
其它一些辅助命令
$ jmap -heap
显示java堆的摘要信息,打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息
$ jmap -histo[:live]
显示堆中对象的统计信息,其中包括每个Java类、对象数量、内存大小(单位:字节)、完全限定的类名。打印的虚拟机内部的类名称将会带有一个’*’前缀。如果指定了live子选项,则只计算活动的对象。