1 故障现象
这天上午,有同事反映公司后台管理系统运行缓慢,运维同事检查发现cpu占用过高,重启服务器后故障消失。
这天下午,有同事也反映后台系统的某模块系统,运行缓慢,多次重启后故障仍然存在,使用top命令查看服务器的情况,发现cpu占用率接近100%。
2 cpu问题定位
定位问题进程
使用了top指令查看资源占用情况,发现PID为11705的进程消耗了大量的CPU资源,达到了780.4
定位问题线程
使用 ps -mp 11705 -o THREAD,tid,time 指令把该11705进程的thread,tid,time给列出来,
发现11707-11715 这段中的线程占用了大量的cpu时间,各个线程占用了12分钟的时间。
查看问题线程堆栈
挑选 11707 这个线程,查看该线程堆栈情况。
步骤:1
先将线程id转成16进制,
jstack pid|grep 11707 -A 30
步骤:2
使用jstack 打印线程堆栈信息
在打印信息中,发现该线程是JVM GC线程。那么现在基本可以确定是内存不足,或内存泄漏导致gc线程持续gc 运行,cpu占用过高。(这种情况类是Effect java 第一章提到的)。
3 内存定位
定位内存区域
使用jstat -gcutil 查看该进程的内存情况
此时可以看到:
E 100.00:伊甸区内存已满;
O 99.98:老年代内存已满;
FGC 117:该进程发生了117次全量GC;
GCT 908.51:该进程GC时间908秒。
根据以上信息,基本可确定是程序代码存在问题。
分析内存对象
使用jmap -histo 指令查看进程的内存对象情况:
1 2 3 4 5 6 | jmap - histo 14062 >> jmap . out ``` 拉日志出来看看,此时可以看到,HashMap$Entry的实例数达到5000W,Integer、Double的实例数达到5000w、2000多W,三者占用了大量的内存。 ## 分析堆栈 使用jstat指令查看进程的堆栈情况: |
jstack 12804 >> jstat.out
`
查找相关的代码:
发现:
发现ActivityUtil.java的477行正在使用HashMap的put方法。
4 代码定位
打开ActivityUtil.java类,定位到477行,代码如下:
发现 Map 的对象巨大,占用了Map对象,使得cpu过高,应该是秒杀活动的礼品对象数据过高。
5 改进
修改代码,对礼品进行分页获取。
6 总结-如何查找最高的java线程
1,使用命令top -p <pid> ,显示你的java进程的内存情况,pid是你的java进程号,比如123
2,按H,获取每个线程的内存情况
3,找到内存和cpu占用最高的线程pid,比如15248
4,执行 printf 0x%x 15248 得到 0x3b90 ,此为线程id的十六进制
5,执行 jstack 123|grep -A 10 3b90,得到线程堆栈信息中3b90这个线程所在行的后面10行
6,查看对应的堆栈信息找出可能存在问题的代码