排查思路
当页面使用卡慢时,首先我们需要排除网速慢、服务器性能差等客观原因;
只剩下主观原因之后,我们需要依次排查 CPU占用、JVM内存泄漏、死锁、线程频繁切换、频繁GC、IO占用等常见原因,然后再去精确定位到具体的代码或者配置问题
前置知识
常用命令
系统资源相关
top 命令
top
命令用于查看进程占用的系统资源占用状况,top -Hp pid
用于查看指定进程的相关线程的系统资源占用状况
vmstat 命令
vmstat
用于指定周期和采集次数的虚拟内存检测工具,可以统计 CPU,swap的使用情况,也用于观察进程的上下文切换
字段说明如下:
- r:运行中的进程数量(当数量大于CPU核数表示有线程阻塞)
- b:等待IO的进程数量
- swpd:使用虚拟内存大小
- free: 空闲物理内存大小
- buff: 用作缓冲的内存大小(内存和硬盘的缓冲区)
- cache: 用作缓存的内存大小(CPU 和内存之间的缓冲区)
- si: 每秒从交换区写到内存的大小,由磁盘调入内存
- so: 每秒写入交换区的内存大小,由内存调入磁盘
- bi: 每秒读取的块数
- bo: 每秒写入的块数
- in: 每秒中断数,包括时钟中断。
- cs: 每秒上下文切换数。
- us: 用户进程执行时间百分比(user time)
- sy: 内核系统进程执行时间百分比(system time)
- wa: IO 等待时间百分比
-
pidstat 命令
JVM 相关
jps:
查看所有 Java 进程- jstat:
用于收集 HotSpot 虚拟机各方面运行数据 - jinfo:
显示虚拟机配置信息 - jmap:
生成堆转储快照 - jhat:
用于分析 heapdump 文件,可以在浏览器上查看分析结果 - jstack:
生成虚拟机当前时刻线程的堆栈快照
常见问题
CPU 占用过高
- 先使用 top 命令查看CPU使用最高的进程号
- 使用
ps H -eo pid,tid,%cpu | grep 进程号
,可以查看当前进程中所有运行的线程信息和CPU占用率,这样我们可以过滤出占用CPU最多的线程号
使用top -Hp 进程号
也可以获得相关线程信息 - 执行
printf '%x' 线程id
获取16进制的线程id ,称为nid 执行
jstack 进程id | grep -A 20 nid
定位到出现问题的方法死锁
jstack 进程id | grep -A 20 deadlock
定位死锁位置内存溢出
执行
jps
查找 java 进程号- 执行
jmap -heap 进程号
获取java堆空间信息 - 执行
jmap -histo:live 进程号
查看进程中存活的对象 - 使用 jConsole 工具
- 使用 jVisualVM 工具
jVisualVM
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=10.44.237.96"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.rmi.port=1099"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=1099"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
线程切换
- 线程频繁切换会导致大量的CPU资源浪费在寄存器、内核、以及虚拟内存的保存和恢复上,导致系统的整体性能下降
当CPU被占用率较高,但是通过 top -Hp pid 命令查看线程占用状态时,各个线程的占用率都比较平均,此时可以考虑时线程频繁切换导致的系统性能问题
使用 vmstat 1 10 查看线程切换信息(1秒打印一次,总共打印10次)
主要关注4个指标:
r:表示等待的进程数量
cs:表示每秒上下文切换次数
us:用户态占用CPU的时间比例
sy:内核态占用CPU的时间比例使用 pidstat -p pid -w 1 10 来查看指定 java 进程内部的线程运行情况,pid指的是运行的java程序进程号
主要关注2指标:
nvcswch/s:线程每秒切换的次数
pid:线程的十进制号
接着将进程号转换为16进制,并配合 jstack 命令即可定位到相关的代码位置
Arthas
Arthas(阿尔萨斯)是阿里推出的一款性能检测工具;可以做到无侵入地监控应用的运行情况
Arthas官方文档
常用命令
dashboard
显示系统当前实时面板
详见:https://arthas.aliyun.com/doc/dashboard.html
thread
thread pid
显示指定线程的堆栈信息thread -n pid
显示最忙碌的前n个线程并打印堆栈thread -b
找出当前阻塞其他线程的线程thread -i time
指定采样间隔
如 thread -n 3 -i 1000
每秒统计最忙的前三个线程
jad
jad java.lang.String
反编译已经被加载的源码和类加载信息-
watch
watch com.xx.Demo doDemo returnObj
查看 demo 类的 doDemo 方法的返回值
watch demo.MathGame primeFactors “{params,target,returnObj}” -x 2 -b -s -n 2
- params:本次调用参数列表
- target:本次调用类的实例
- returnObj:本次调用的返回对象
- -x:属性遍历深度,默认为1
- -b:在函数执行前观察
- -s:在函数返回后观察
- -n:执行次数
trace
查看方法的调用路径
trace demo.MathGame run
查看 MathGame 类中 run 方法调用其它方法的调用路径
run() → primeFactors() → print()stack
查看方法的被调用路径
stack demo.MathGame primeFactors
查看 MathGame 中 primeFactors 方法被调用路径