最近一段时间 某台服务器上的一个应用总是隔一段时间就自己挂掉 用top看了看 从重新部署应用开始没有多长时间CPU占用上升得很快
排查步骤
1.使用top 定位到占用CPU高的进程PID
top
2.通过ps aux | grep PID命令
获取线程信息,并找到占用CPU高的线程
ps -mp pid -o THREAD,tid,time | sort -rn
3.将需要的线程ID转换为16进制格式
printf "%x\n" tid
4.打印线程的堆栈信息 到了这一步具体看堆栈的日志来定位问题了
jstack pid |grep tid -A 30
---------------------------------------------------------------------------- 华丽的分割线 ------------------------------------------------------------------------------------------------------------------
top 可以看出PID 733进程 的占用CPU 172%
查找进程733下的线程 可以看到TID 线程775占用了96%且持有了很长时间 其实到这一步基本上能猜测到应该是 肯定是那段代码发生了死循环
ps -mp 733 -o THREAD,tid,time | sort -rn
线程ID转换为16进制格式
printf "%x\n" 775
查看java 的堆栈信息
jstack 733 |grep 307 -A 30
显然是 SmsQueueServiceImpl 中的produceMissSms 和 consumeMissSms 方法有问题
ps -mp 21053 -o THREAD,tid,time | sort -rn
printf "%x\n" 21059
5243
有时候jstack打印的数据非常少
jstack 21053|grep 5243 -A 30有时候提示
Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
可以使用
su - root -c "/opt/jvm/jdk1.8.0_192/bin/jstack 3749|grep 34d8 -A 30"
强制指定运行jstack的用户,以及指定jstack运行的路径。
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f0374022800 nid=0x5243 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f0374024000 nid=0x5244 runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f0374026000 nid=0x5245 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f0374027800 nid=0x5246 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f0374029800 nid=0x5247 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f037402b000 nid=0x5248 runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f0374dda800 nid=0x526b waiting on condition
JNI global references: 2946
没啥有用的信息
jstat -gcutil pid 2000 10(显示个数)
jstat -gcutil 14063 2000 10
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 100.00 99.99 26.31 42 21.917 218 1484.830 1506.747
0.00 0.00 100.00 99.99 26.31 42 21.917 218 1484.830 1506.747
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 220 1505.439 1527.355
0.00 0.00 100.00 99.99 26.31 42 21.917 220 1505.439 1527.355
0.00 0.00 100.00 99.99 26.31 42 21.917 220 1505.439 1527.355
从输出信息可以看出,Eden区内存占用100%,Old区内存占用99.99%,Full GC的次数高达220次,并且频繁Full GC,Full GC的持续时间也特别长,平均每次Full GC耗时6.8秒(1505.439/220)。根据这些信息,基本可以确定是程序代码上出现了问题,可能存在不合理创建对象的地方
还有个程序是arthas下面一个监测脚本叫show-busy-java-threads
直接运行./show-busy-java-threads可用列出cpu最高的前5个线程
再说下arthas是一个很好用的监测程序arthas-boot.jar
java -jar arthas-boot.jar 启动起来以后选择需要监控的java编号
可以使用的命令dashboard可以看目前运行的一个图形界面线程监控
thread可以列出现在占用最高的线程列表,thread -n 3列出占用最高的线程详情
有时候cpu 100%以后运行不了任何打印线程的命令,多试几次,再cpu稍微降低的时候运行上述命令,只要能打印一次就可以找到代码故障位置进行排查。
还可以用jmap -dump:live,format=b,file=heap_dump pid保存一下dump文件。然后在pc上面用MemoryAnalyzer分析一下