这里不是流水一样的介绍功能怎么用,就说说线上遇到的问题,我们通常怎么排查,排查的几种情况。
1.内存溢出,出现OutOfMemoryError,这个问题如何排查
2.CPU使用猛增,这个问题如何排查?
3.进程有死锁,这个问题如何排查?
4.JVM参数调优
第一步:通过jmap -histo命令查看系统内存使用情况
使用的命令:
jmap -histo -pid(进程id)
通过这个命令,我们可以看出当前哪个对象最消耗内存。
上面这个运行结果是我启动了本地的一个项目,然后运行【jmap -histro 进程号】运行出来的结果,直 接去了其中的一部分。通过这里我们可以看看大的实例对象中,有没有我们自定义的实例对象。通过这 个可以排查出哪个实例对象引起的内存溢出。
除此之外, Total汇总数据可以看出当前一共有多少个对象,暂用了多大内存空间。这里是有约860w个 对象,占用约923M的空间。
第二步:分析内存溢出,查看堆空间占用情况
使用命令
jmap -heap -pid (进程id)
比如,我本地启动了一个项目,想要查看这个项目的内存占用情况
[root ~]# jmap -heap 15271
Attaching to process ID 15271, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.77-b03
using thread-local object allocation.
Garbage-First (G1) GC with 2 thread(s)
Heap Configuration:
MinHeapFreeRatio
MaxHeapFreeRatio
MaxHeapSize
NewSize
MaxNewSize
OldSize
NewRatio
SurvivorRatio
MetaspaceSize
= 40
= 70
= 536870912 (512.0MB)
= 1363144 (1.2999954223632812MB)
= 321912832 (307.0MB)
= 5452592 (5.1999969482421875MB)
= 2
= 8
= 134217728 (128.0MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize
G1HeapRegionSize
= 134217728 (128.0MB)
= 1048576 (1.0MB)
Heap Usage:
G1 Heap:
regions = 512
capacity = 536870912 (512.0MB)
used = 283115632 (270.00010681152344MB)
free = 253755280 (241.99989318847656MB)
52.73439586162567% used
G1 Young Generation:
Eden Space:
regions = 132
capacity = 305135616 (291.0MB)
used = 138412032 (132.0MB)
free = 166723584 (159.0MB)
45.36082474226804% used
Survivor Space:
regions = 32
capacity = 33554432 (32.0MB)
used = 33554432 (32.0MB)
free = 0 (0.0MB)
100.0% used
G1 Old Generation:
regions = 110
capacity = 198180864 (189.0MB)
used
free
= 111149168 (106.00010681152344MB)
= 87031696 (82.99989318847656MB)
56.08471259868965% used
48916 interned Strings occupying 5031568 bytes.
下面来看看参数的含义
堆空间配置信息
Heap Configuration:
/**
* 空闲堆空间的最小百分比,计算公式为:HeapFreeRatio =
(CurrentFreeHeapSize/CurrentTotalHeapSize) * 100,值的区间为0 * 到100,默认值为
40。如果HeapFreeRatio < MinHeapFreeRatio,则需要进行堆扩容,扩容的时机应该在每次垃圾回收之 后。
*/
MinHeapFreeRatio = 40
/**
* 空闲堆空间的最大百分比,计算公式为:HeapFreeRatio =
(CurrentFreeHeapSize/CurrentTotalHeapSize) * 100,值的区间为0
* 到100,默认值为 70。如果HeapFreeRatio > MaxHeapFreeRatio,则需要进行堆缩容,缩容的 时机应该在每次垃圾回收之后
*/
MaxHeapFreeRatio = 70
/**JVM 堆空间允许的最大值*/
MaxHeapSize = 2065694720 (1970.0MB)
/** JVM 新生代堆空间的默认值*/
NewSize = 1363144 (1.2999954223632812MB)
/** JVM 新生代堆空间允许的最大值 */
MaxNewSize = 1239416832 (1182.0MB)
/** JVM 老年代堆空间的默认值 */
OldSize = 5452592 (5.1999969482421875MB)
/** 新生代 (2个Survivor区和Eden区 )
*与老年代 (不包括永久区) 的堆空间比值,表示新生代:
*老年 代=1:2
*/
NewRatio = 2
/** 两个Survivor区和Eden区的堆空间比值为 8,表示 S0 : S1 :Eden = 1:1:8 */
SurvivorRatio
/** JVM 元空间的默认值 */ MetaspaceSize = 8
= 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
/** JVM 元空间允许的最大值 */
MaxMetaspaceSize = 17592186044415 MB
/** 在使用 G1 垃圾回收算法时,JVM 会将 Heap 空间分隔为若干个 Region,
* 该参数用来指定每个 Region 空间的大小
*/
G1HeapRegionSize = 1048576 (1.0MB)
G1堆使用情况
G1 Heap:
regions = 512
capacity = 536870912 (512.0MB)
used = 283115632 (270.00010681152344MB)
free = 253755280 (241.99989318847656MB)
52.73439586162567% used
G1 的 Heap 使用情况,该 Heap 包含 512 个 Region,结合上文每个 RegionSize=1M,
因此
Capacity = Regions * RegionSize = 512 * 1M = 1970M,
已使用空间为270.00010681152344MB,
空闲空间为 241.99989318847656MB,
使用率为 52.73439586162567%。
G1年轻代Eden区使用情况
G1 Young Generation:
Eden Space:
regions = 132
capacity = 305135616 (291.0MB)
used = 138412032 (132.0MB)
free = 166723584 (159.0MB)
45.36082474226804% used
G1年轻代Survivor区使用情况
Survivor Space:
regions = 32
capacity = 33554432 (32.0MB)
used
free = 33554432 (32.0MB)
= 0 (0.0MB)
100.0% used
G1老年代使用情况
G1 Old Generation:
regions = 110
capacity = 198180864 (189.0MB)
used
free = 111149168 (106.00010681152344MB)
= 87031696 (82.99989318847656MB)
56.08471259868965% used
通过上面的命令,我们就能知道当前系统堆空间的使用情况了,到底是老年代有问题还是新生代有问 题。
我们可以通过Jstack找出占用cpu最高的线程的堆栈信息,下面来一步一步分析。
第一步:运行代码,使用top命令查看cpu占用情况
第二步:使用top -p 命令查看飙高进程
top -p 15271
[root~]# top -p 15271
top - 14:06:27 up 88 days, 4:29, 5 users, load average: 4.14, 2.32, 1.32
Tasks: 0 total, 0 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 90.2 us, 4.0 sy, 0.0 ni, 5.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB
Mem : 8009264 total, 1529888 free, 4388024 used, 2091352 buff/cache
KiB Swap: 8388604 total, 8388604 free, 0 used. 3194448 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
第三步:按H,获取每个线程的内存情况
需要注意的是,这里的H是大写的H。
第四步:找到内存和cpu占用最高的线程tid
过上图我们看到占用cpu资源最高的线程有两个,线程号分别是4018362, 4018363。我们一第一个为 例说明,如何查询这个线程是哪个线程,以及这个线程的什么地方出现问题,导致cpu飙高。
第五步:将线程tid转化为十六进制
67187778是线程号为4013442的十六进制数。具体转换可以网上查询工具。
第六步:执行[ jstack 4018360 |grep -A 10 67187778] 查询飙高线
程的堆栈信息
接下来查询飙高线程的堆栈信息
jstack 4013440|grep -A 10 67190882
4013440:表示的是进程号
67187778: 表示的是线程号对应的十六进制数
通过这个方式可以查询到这个线程对应的堆栈信息
从这里我们可以看出有问题的线程id是0x4cd0, 哪一句代码有问题呢, Math类的22行。
第七步:查看对应的堆栈信息找出可能存在问题的代码
上述方法定位问题已经很精确了,接下来就是区代码里排查为什么会有问题了。
备注:上面的进程id可能没有对应上,在测试的时候,需要写对进程id和线程id
jvm调优通常使用的是Jstat命令
1. 垃圾回收统计 jstat -gc
jstat -gc 进程id
上面的参数分别是什么意思呢?先识别参数的含义,然后根据参数进行分析
S0C: 第一个Survivor区的容量
S1C: 第二个Survivor区的容量
S0U: 第一个Survivor区已经使用的容量
S1U:第二个Survivor区已经使用的容量
EC: 新生代Eden区的容量
EU: 新生代Eden区已经使用的容量
OC: 老年代容量
OU:老年代已经使用的容量
MC: 方法区大小 (元空间)
MU: 方法区已经使用的大小
CCSC:压缩指针占用空间
CCSU:压缩指针已经使用的空间
YGC: YoungGC已经发生的次数
YGCT: 这一次YoungGC耗时
FGC: Full GC发生的次数
FGCT: Full GC耗时
GCT: 总的GC耗时,等于YGCT+FGCT
连续观察GC变化的命令
jstat -gc 进程ID 间隔时间 打印次数
这样就连续打印了10次gc的变化,每次隔一秒。
这个命令是对整体垃圾回收情况的统计,下面将会差分处理
2.堆内存统计
这个命令是打印堆内存的使用情况。
jstat -gccapacity 进程ID
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0C:第一个Survivor区大小
S1C:第二个Survivor区大小
EC:Eden区的大小
OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:当前老年代大小
OC: 当前老年代大小
MCMN: 最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代gc次数
FGC:老年代GC次数
3.新生代垃圾回收统计
jstat -gcnew 进程ID [ 间隔时间 打印次数]
S0C:第一个Survivor的大小
S1C:第二个Survivor的大小
S0U:第一个Survivor已使用大小
S1U:第二个Survivor已使用大小
TT: 对象在新生代存活的次数
MTT: 对象在新生代存活的最大次数
DSS: 期望的Survivor大小
EC:Eden区的大小
EU:Eden区的使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
4. 新生代内存统计
jstat -gcnewcapacity 进程ID
参数含义:
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0CMX:Survivor 1区最大大小
S0C:当前Survivor 1区大小
S1CMX:Survivor 2区最大大小
S1C:当前Survivor 2区大小
ECMX:最大Eden区大小
EC:当前Eden区大小
YGC:年轻代垃圾回收次数
FGC:老年代回收次数
5. 老年代垃圾回收统计
jstat -gcold 进程ID
MC:方法区大小
MU:方法区已使用大小
CCSC:压缩指针类空间大小
CCSU:压缩类空间已使用大小
OC:老年代大小
OU:老年代已使用大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间,新生代+老年代
6. 老年代内存统计
jstat -gcoldcapacity 进程ID
7. 元数据空间统计
jstat -gcmetacapacity 进程ID
8.整体运行情况
jstat -gcutil 进程ID