简单记录下排查过程
1.top找到tomcat进程
2.假设把cpu吃满的tomcat进程pid是20172,ps -mp 20172 -o THREAD,tid,time查看线程情况,找到把cpu吃满的线程
3.上图中的TID需要转成16进制,可以用printf "%x\n",假设把cpu吃满的TheaddId为20174
4.然后用jstack 20172|grep 4ece -A 30命令dump线程,20172是进程PID,4ece是16进制的TID,注意jstack需在java/bin目录下运行。
可以看到线程状态,一般有:unnable(正在运行)、waiting for monitor(主动等待)、waiting for monitor entry(死锁)
死锁需要额外注意,由于线程是动态变化的,可以每隔30秒dump一次。
但如果是线上问题,需要迅速解决问题,最直接的就是kill重启,这时需要先记录线程堆栈日志,恢复线上生产后再查找问题。可以先记录CPU100%的TID,再使用jstack pid > 20180919.log导出堆栈日志,后续再根据线程TID查找问题点,注意这里的TID也是16进制的。
拿到Tid后,如果需要观察GC状态(有时cpu100可能是由于内存泄漏导致cpu被GC线程吃满),可以使用Jstat工具,和jstack一样也是位于jdk的bin目录下,可以用jstat -gcutil 20172 2000 10查看运行时gc信息,20172即Pid。
图中可以看到Eden和old区内存已经满了,FGC高达近7k次,FGCT(full gc time)高达36602秒,36602/7000 =5.22s,也就是说每次FGC时间长达5s,基本可以确定是内存泄漏。可以用Jmap查看具体的内存状态,Jmap同样位于bin目录下,是jdk提供的内存映射工具。
下次遇到这种状况建议直接为服务开启JMX,从本地或开发环境用JvisualVM监控,快速定位问题。