JVM:利用jstat查看GC信息及堆内存设置(二)

0. 引言

上一章我们讲解了排查OOM问题的思路和基本操作,这一节,我们接着讲解如何解读垃圾回收(GC)频率、效率等信息

1. 环境准备

1、首先继续启动我们上一章演示的代码:

java -jar -Xms200M -Xmx200M cpu_oom_demo-0.0.1-SNAPSHOT.jar

2、查看启动的进程pid

jps -l

在这里插入图片描述

2. 日志查询指令 jstat

要查询GC信息,我们可以通过jstat指令实现

jstat指令的命令格式为:jstat [options] pid [interval] [count]

  • options: 统计选项,具体如下所示,比较常用的是-gc, -gcutil
选项 说明
-gc 统计垃圾回收的堆信息,单位为空间字节数,即单位为KB
-gcutil 统计垃圾回收的堆信息,单位为空间的百分比
-class 统计类加载器的信息
-compile 统计编译行为信息
-gccapacity 统计不同区域(新生代、老年代、永久代)的堆容量信息
-gccause 统计引起垃圾回收的事件
-gcnew 统计垃圾回收时,新生代的情况
-gcnewcapacity 统计垃圾回收时,新生代堆空间容量
-gcold 统计垃圾回收时,老年代的情况
-gcoldcapacity 统计垃圾回收时,老年代堆空间容量
-gcpermcapacity 统计垃圾回收时,永久代的堆空间容量
  • pid: java进程号
  • interval: 间隔时间,单位为秒或毫秒
  • count: 打印次数,不填则默认一直打印

2. GC分析

1、统计垃圾回收的堆信息 jstat -gc

每秒统计垃圾回收的堆信息,打印10次,

jstat -gc 1994 1000 10

在这里插入图片描述
参数详解:

S0C:第一个幸存区的大小,单位KB
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间

如上所示的java进程,老年代空间大小为133M左右,使用的老老年代空间为6M左右,所以老年代空间充足,再看FGC与YGC,分别为1和4,即老年代回收次数为1,年轻代回收次数为4。消耗还很小,说明目前进程正常。

现在我们来看一个内存溢出的进程信息:

可以看到老年代占用满了,并且GCT垃圾回收时间上升,但是垃圾并没有被回收调,占用依旧拉满,也就是我们常说的垃圾回收不掉信息。

在这里插入图片描述

2、查看垃圾回收的空间占比 jstat -gcutil

同时我们也可以利用jstat -gcutil 看看空间占比情况(这里我重新模拟了OOM问题的发生,可以看到内存占比的变化)

jstat -gcutil 1994 1000

在这里插入图片描述
参数详解:

S0:幸存1区当前使用比例
S1:幸存2区当前使用比例
E:伊甸园区使用比例
O:老年代使用比例
M:元数据区使用比例
CCS:压缩类使用比例
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间

可以看到老年代使用比例O,从4.68%逐步飙升到了100%,而垃圾回收时间也从0.034上升到0.710,并且后续显示老年代空间比一直没有下降,说明垃圾没有被回收调,明显出现了内存溢出。

3、统计引起垃圾回收的事件 jstat -gccause

jstat -gccause 1994 1000

在这里插入图片描述
参数详解:

S0:幸存1区当前使用比例
S1:幸存2区当前使用比例
E:伊甸园区使用比例
O:老年代使用比例
M:元空间使用比例
CCS:压缩类使用比例
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收所用的时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收所用的时间
GCT:垃圾回收的所用的总时间
LGCC:上次垃圾回收的原因
GCC:当前垃圾回收的原因

3. 堆内存设置

如上统计GC日志发现在频繁GC,且GC回收效率一直不高的情况,一是通过上一章讲解的OOM排查思路进行排查内存溢出的原因,二是如果知道了原因,比如是突然上来的用户流量高峰,那么这种也不是代码问题,我们就需要对流量进行限流,或者针对服务器配置进行调整。

比如上述所示,如果发现堆内存不够用了,我们可以调整程序的堆内存:

-Xms:程序启动时占用的内存大小,此值可以和-Xmx相同,避免每次垃圾回收后重新分配内存
-Xmx:程序运行时的最大可占用的内存大小
-Xmn:年轻代的内存大小,整个堆大小=年轻代 + 老年代,官方建议大小为堆空间的1/3,年轻代中又细分为伊甸区、幸存1区、幸存2区,其比例默认为8:1:1。如果想要调整伊甸区占年轻代的比例,可以通过-XX:SurvivorRatio=N来设置,N/(N+2)表示伊甸区的内存占用比例,相对应的幸存区就是1/(N+2)。需要注意的是jdk1.8之后才将持久代与堆隔开,属于物理内存。所以严格意义上来讲,jdk1.8之前,堆大小=年轻代 + 老年代 + 持久代
-XX:NewRatio=N:表示老年代与年轻代的内存比例,默认为2,即2:1,相当于年轻代占堆内存空间的1/3,老年代占2/3
-XX:PretenureSizeThreshold:大对象阈值,单位为字节Byte(1M=1024KB, 1KB=1024Byte),如果对象超过这个值,就会直接进入老年代,不会进入年轻代,默认值为0

java -jar -Xms2g -Xmx2g -Xmn512m cpu_oom_demo-0.0.1-SNAPSHOT.jar

总结

本期关于GC信息的查询就到此结束了,下一期我们继续讲解JVM的实操问题

猜你喜欢

转载自blog.csdn.net/qq_24950043/article/details/129777267