一日,收到服务器 CPU 资源占用满的报警,如下,随抓紧排查:
top
首先使用最简单的工具 top
一下,查看是哪个进程占用了大量的 CPU 资源,如下:
可以看到的是一个 Java
进程把所有的 CPU 资源都给占用掉了,一个完整的 Java 程序是由大量的线程组成的,也就是说进程里面的某一个或多个线程可能占用了大量的 CPU 资源,只需找出它即可。
top -Hp <pid>
使用命令 top -Hp <pid>
即可查看指定 pid
进程下的线程情况,上图查看到这个 Java 进程的 pid 为 1
,所以执行 top -Hp 1
得到如下图:
由上图可见,pid
为 55
的这个线程占用了大量的 CPU 资源。这里已经定位到了在系统中的 pid,接下来要知道的是这个 pid 具体对应的是 Java 中的哪个线程?哪个类?甚至是在哪一行代码?这样才能更好的定位到代码的问题所在。
printf "%x\n" <pid>
使用 printf "%x\n" 55
把上一步中找到的这个 pid 55 转换成十六进制格式。
$ printf "%x\n" 55
37
jstack
jstack 是 Java 虚拟机自带的一种堆栈跟踪工具。jstack 用于打印出给定的
Java 进程 ID
或core file
或远程调试服务
的 Java 堆栈信息。
这里使用 jstack 1
来列出 Java 进程的堆栈信息,并删选出来指定线程 37
(上步所得十六进程 pid)的信息。
$ jstack 1 | grep nid=0x37
"general-thread-pool-1" #23 prio=5 os_prio=0 tid=0x00007f4cc08be800 nid=0x37 runnable [0x00007f4c56afd000]
上一步找到了对应的线程 general-thread-pool-1
,但是这个线程具体运行的哪一块的代码还没有找到,继续之。
-A 7
:把 grep 筛选出来的目标向下延伸指定行。因为命令jstack
本身就把堆栈信息打出来了,所以只需要把筛选信息多显示一点就可以看到堆栈信息,也就找到是哪里引起的 CPU 异常了。
$ jstack 1 | grep -A 7 nid=0x37
"general-thread-pool-1" #23 prio=5 os_prio=0 tid=0x00007f4cc08be800 nid=0x37 runnable [0x00007f4c56afd000]
java.lang.Thread.State: RUNNABLE
at com.lynchj.CollectExecTask.lambda$readyTask$1(CollectExecTask.java:97)
at com.lynchj.CollectExecTask$$Lambda$837/1786872722.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
文章评论