问题解决:记录一次解决Java应用CPU居高不下的过程

问题场景

线上有一个项目,在运行过程中,CPU会随着时间逐步递增,并最终占满全部CPU,导致应用无法响应,形成故障。本篇博文主要是针对此种情况进行问题解决并梳理解决步骤。

问题环境

软件 版本
Centos 6.4
JDK 1.6

问题原因

1. top命令查看进程情况

我们先用top命令查看对应的进程,效果如下图,我们可以知道目前程序已经占用了10CPU核,属于比较高的CPU占用率了。
在这里插入图片描述

2. top命令查看具体的进程内部的线程情况

接下来,我们使用以下命令访问对应的进程内部,查看是哪个线程占用了CPU资源,如下:

top -H -p 24544

结果如下图:
在这里插入图片描述
我们可以从上图知道已经有10个线程的CPU占用率都达到了96%。我们随机抽取一个线程,这里我们选取pid24937的线程,并转换为16进制,截图如下:
在这里插入图片描述

3. 使用jstack命令获取进程的堆栈信息

之后,我们使用以下命令将该进程的堆栈信息dump下面,如下:

 jstack 24544 > 24544_error.log

4. 根据第二步的16进制的pid在堆栈信息里面进行搜索获取具体的线程情况

并根据上面拿到的16进制编码,在24544_error.log进行搜索查找,可以找到以下的线程,如下图:

在这里插入图片描述

5. 查看具体的代码情况

根据第4步获取的线程情况,找到项目对应的代码位置,下图红框部分是阻塞的代码所在:
在这里插入图片描述

乍一看,感觉就是HashMap的死循环问题,博主查看了XssFilter.invalidMap的赋值情况,发现在过滤器XssFilter的过滤方法里面,对XssFilter.invalidMap进行了初始化,如下图

在这里插入图片描述
这样就会导致每次链接经过过滤器的时候,都会初始化一次XssFilter.invalidMap。而从代码可以看到XssFilter.invalidMapHashMap对象,这是非线程安全类。在每次调用XssFilter.invalidMap进行遍历的时候,如果刚好有其他线程进行了初始化,就会出现死循环的情况。在高并发的情况下,这种死循环情况的发生率就会很高了。所以项目在线上跑的时候,一般在高峰期就会出现这种情况,导致了CPU飙高,进而导致项目不可访问。

解决方案

既然知道是HashMap的死循环问题,那对HashMap的初始化进行加锁即可。咨询了原开发人员,这个初始化一次即可。我这里提供一种解决方式,使用双重检查锁:

if (null == invalidMap) {
    
    
    synchronized (invalidMap) {
    
    
        if (null == invalidMap) {
    
    
            // 初始化invalidMap 
        }
    }
}

这样只需要初始化一次就可以,不会出现重复初始化。

结果

更新了补丁之后,目前项目运行正常。问题得到解决!!!

总结

编写代码的时候,还得多思考,多考虑高效和安全。本篇博文主要是讲述了整个解决过程的思路,一般按照这种思路,基本可以解决很多问题了。

随缘求赞

如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以点击关注
可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!
在这里插入图片描述
拜拜

猜你喜欢

转载自blog.csdn.net/u013084266/article/details/109311302