问题 – 异常占用大量 CPU 资源排查

  一日,收到服务器 CPU 资源占用满的报警,如下,随抓紧排查:

  • top

  首先使用最简单的工具 top 一下,查看是哪个进程占用了大量的 CPU 资源,如下:

  可以看到的是一个 Java 进程把所有的 CPU 资源都给占用掉了,一个完整的 Java 程序是由大量的线程组成的,也就是说进程里面的某一个或多个线程可能占用了大量的 CPU 资源,只需找出它即可。

  • top -Hp <pid>

  使用命令 top -Hp <pid> 即可查看指定 pid 进程下的线程情况,上图查看到这个 Java 进程的 pid 为 1,所以执行 top -Hp 1 得到如下图:

  由上图可见,pid55 的这个线程占用了大量的 CPU 资源。这里已经定位到了在系统中的 pid,接下来要知道的是这个 pid 具体对应的是 Java 中的哪个线程?哪个类?甚至是在哪一行代码?这样才能更好的定位到代码的问题所在。

  • printf "%x\n" <pid>

  使用 printf "%x\n" 55 把上一步中找到的这个 pid 55 转换成十六进制格式。

$ printf "%x\n" 55
37
  • jstack

jstack 是 Java 虚拟机自带的一种堆栈跟踪工具。jstack 用于打印出给定的 Java 进程 IDcore 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)

发表评论

电子邮件地址不会被公开。 必填项已用*标注