问:“线上一台服务器 CPU 使用率100% 了,如果你碰到这样的情况,如何排查并找到问题原因?

这是一个套路题,掌握了套路,不仅能解决面试官,还能解决问题。这个问题应该怎么排查呢?

模拟一个高 CPU 场景

先用一段程序创建几个线程,将其中一个线程设置成高 CPU 使用率的。

public static void main(String[] args)  {
   for (int i = ; i < 10; i++) {
     Thread thread = new Thread(() -> {
       System.out.println(Thread.currentThread().getName());
       try {
         Thread.sleep(30 * 60 * 1000);
       }catch (Exception e){
         e.printStackTrace();
       }
     });
     thread.setName("thread-" + i);
     thread.start();
   }

   Thread highCpuThread = new Thread(() -> {
     int i = ;
     while (true) {
       i++;
     }
   });
   highCpuThread.setName("HighCpu");
   highCpuThread.start();
 }

运行这段程序后,前面 10 个线程都处于休眠状态,只有最后一个线程会持续的占用 CPU 。

运行这段程序,然后就可以开始一些列的操作来发现问题原因了。

  1. 排查步骤
  1. 1第一步,使用 top 找到占用 CPU 最高的 Java 进程

在真实环境中,首先要确认是不是 Java 程序造成的,如果有系统监控工具,可能会直接在预警信息里告诉你是有哪个进程造成的,但也有可能不知道,需要我们手动排查。在面试场景中,面试官告诉你是 Java 占用的 CPU 过高,怎么解决。这一步就是一个 top命令。

cpu升高的原因java java开发 cpu过高_top命令

使用 top命令发现占用 CPU 99.7% 的线程是 Java 进程,进程 PID 为 13731。

  1. 2第二步,用 top -Hp 命令查看占用 CPU 最高的线程

上一步用 top命令找到了那个 Java 进程。那一个进程中有那么多线程,不可能所有线程都一直占着 CPU 不放,这一步要做的就是揪出这个线程,当然有可能不止一个。

执行top -Hp pid命令,pid 就是前面的 Java 进程,这个例子中是 13731 ,完整命令为:

top -Hp 13731,执行效果如下

cpu升高的原因java java开发 cpu过高_cpu升高的原因java_02

可以看到占用 CPU 最高的那个线程 PID 为 13756。

然后将 13756转换为 16 进制的,后面会用到,可以用在线程进制转换的网站直接转换,转换结果为 0x35bc

  1. 3第三步,保存线程栈信息

当前 Java 程序的所有线程信息都可以通过 jstack命令查看,用jstack命令将第一步找到的 Java 进程的线程栈保存下来。

jstack 13731 > thread_stack.log

  1. 第四步,在线程栈中查找最贵祸首的线程

第二步已经找到了这个占用CPU过高的线程 PID,并把它转换成了 16 进制的,第三步保存下来的线程栈中有所有线程的 PID 16 进制信息,在线程栈中查找这个16进制的线程 id (0x35bc)。

cpu升高的原因java java开发 cpu过高_cpu升高的原因java_03

现在一目了然了,线程名称、线程状态、以及哪行代码消耗了最多的 CPU 都很清楚了。