乐趣区

关于java:因死循环导致CPU飙升到100的问题排查记录

背景

忽然收到运维告警邮件,线上的一台负责解决定时工作的服务器 CPU 飙升到了 100%,立马放下手头工作开始了缓和的排查工作。

之前也写过一篇文章 JVM 调优之 Java 过程耗费 CPU 过高

过程

1、确定 Java 利用过程编号

应用 jps 或 ps -ef|grep java 命令确定想要剖析的利用的过程编号

2、查看 Java 利用中线程 CPU 占比

应用 top -p 109023 -H 命令查看指定过程下的线程 cpu 占用比例,剖析是具体哪个线程占用率过高,其中 109023 就是通过第一步确定下来的过程编号

从 top 命令列出来的线程信息中找出对应占用 cpu 很高的线程,并将线程号转化为十六进制的模式

printf “%x\n” 201106 失去对应的十六进制 31192

3、查看线程信息

从中抉择占比拟高的线程的编号(PID),并将该 PID 转换为 16 进制。通过 jstack 109023 |grep 31192

通过该命令能够剖析出线程的具体信息,再通过相应的解决办法来解决 cpu 占用过高的问题。

后果

最终排查发现是之前有集体在定时工作这里埋了一个坑,导致了死循环而引发的问题,代码大抵如下

public static void main(String[] args) {
        int beginId = 1;
        // 1. 查出来所有须要解决的流水信息
        List<Phone> needHandlePhoneList = listNeedHandlePhone(beginId);
        if (needHandlePhoneList.size() == 0){return;}
        // 2. 开始解决
        while (needHandlePhoneList.size() > 0){
            // 执行逻辑...
            // bug: 总数数据库中只有 3 条待处理记录,第一次查出 3 条,最初一条的 id 是 3,那么此处的 beginId 便为 3
            beginId = needHandlePhoneList.get(needHandlePhoneList.size()-1).getId();
            // bug: 下面查出来的 beginId 是 3,在依照 >= 3 去是数据库中查问,还是会查到一条记录,如此 needHandlePhoneList 始终不为空,产生死循环
            needHandlePhoneList = listNeedHandlePhone(beginId);
        }

    }

    private static List<Phone> listNeedHandlePhone(int beginId) {
        /**
         * select * from phone where id >= #{beginId} order by id limit 100
         *
         * >= 存在问题,与内部逻辑配合会产生死循环,需改成 >
         */
        return initPhoneList();}

本篇文章如有帮忙到您,请给「翎野君」点个赞,感谢您的反对。

退出移动版