zoukankan      html  css  js  c++  java
  • 服务器CPU又爆了?Linux快速排查Java程序占用CPU很高的方法

    这个问题可以说是 Java 面试的高频面试题了,有很多面试官都喜欢问这个问题,问题可能是下面这样的。

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

    1.场景模拟

    当我们真碰到这个问题的时候应该怎么排查呢?

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

    public static void main(String[] args)  {
      for (int i = 0; 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 = 0;
        while (true) {
          i++;
        }
      });
      highCpuThread.setName("HighCpu");
      highCpuThread.start();
    }
    

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

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

    2.排查步骤


    第一步,使用 top 找到占用 CPU 最高的 Java 进程

    在真实环境中,首先要确认是不是 Java 程序造成的,如果有系统监控工具,可能会直接在预警信息里告诉你是有哪个进程造成的,但也有可能不知道,需要我们手动排查。

    如果是在面试场景中,这个问题可能不需要确认,毕竟 Java 面试,面试官可能直接就告诉你是 Java 占用的 CPU 过高。

    这一步也非常简单,就是一个 top命令而已,基本上所有同学都用过这个命令吧。

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

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

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

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

    top -Hp 13731,执行之后的效果如下

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

    然后将 13756转换为 16 进制的,后面会用到,可以用在线进制转换的网站直接转换,转换结果为 0x35bc;
    也可以直接输入命令转换,printf "%x" 线程id,如下图

    第三步,保存线程栈信息

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

    jstack 13731 > thread_stack.log
    

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

    第二步已经找到了这个罪魁祸首的线程 PID,并把它转换成了 16 进制的,第三步保存下来的线程栈中有所有线程的 PID 16 进制信息,我们在线程栈中查找这个16进制的线程 id (0x35bc)。

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

    3.实战演练

    昨天刚好测试反馈说我们的转测环境上存在cpu占用过高的情况,于是刚好按照以上步骤进行验证下:

    1.先执行top命令,截取部分图如下:


    可以看到50262这个进程导致的cpu过高,并且是java程序,最后一列

    2.执行top -Hp pid命令,查看具体的线程



    可以看到是52018这个线程占用了cpu过高的使用率,使用在线进制转换,将其转为16进制,结果为cb8c,即0xcb8c.
    在线进制转换地址

    3.使用jstack将进程内的线程栈信息保存

    由于转测环境没有保存权限,我直接展示到桌面复制出来后进行的搜索查询,这里仅截取部分片段

    根据第二步中的16进制线程id查询信息,内容如下:

    "Thread-8" #27 daemon prio=5 os_prio=0 tid=0x00007f692684d000 nid=0xcb8c runnable [0x00007f6940109000]
       java.lang.Thread.State: RUNNABLE
            at java.util.HashMap.putVal(HashMap.java:629)
            at java.util.HashMap.put(HashMap.java:612)
            at java.util.HashSet.add(HashSet.java:220)
            at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
            at java.util.HashSet.<init>(HashSet.java:120)
            at com.huawei.ivas.externals.config.DataSourceRoutingCache.getAllDatasources(DataSourceRoutingCache.java:140)
            at com.huawei.ivas.externals.config.TaskLoadBalanceCache.getNodeArray(TaskLoadBalanceCache.java:196)
            at com.huawei.ivas.service.comm.sms.receiver.RbtSmsProcessThread.run(RbtSmsProcessThread.java:68)
    

    可以看到具体的导致问题的代码和行号,我们搜索RbtSmsProcessThread这个类,并定位到68行:


    至此定位到导致占用cpu过高的问题代码

    艾欧尼亚,昂扬不灭,为了更美好的明天而战(#^.^#)
  • 相关阅读:
    树莓派研究笔记(2)-- 安装Nginx 服务器,PHP 和 SQLite
    树莓派研究笔记(1)-- 安装Mono
    Qemu虚拟机 玩树莓派最新版系统 (截止2017-04-10)
    CLRInjection
    CLRMonitor
    Xamarin Mono for VS开发窗体标题(Title)乱码解决方案
    精美3D中国象棋
    怀旧系列(5)----大学时代的疯狂
    怀旧系列(4)----文曲星编程GV-Basic
    怀旧系列(3)----Pascal
  • 原文地址:https://www.cnblogs.com/lovelywcc/p/13995883.html
Copyright © 2011-2022 走看看