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,查看对应的堆栈信息找出可能存在问题的代码