文章目录
问题场景
线上有一个项目,在运行过程中,CPU
会随着时间逐步递增,并最终占满全部CPU
,导致应用无法响应,形成故障。本篇博文主要是针对此种情况进行问题解决并梳理解决步骤。
问题环境
软件 | 版本 |
---|---|
Centos | 6.4 |
JDK | 1.6 |
问题原因
1. top命令查看进程情况
我们先用top
命令查看对应的进程,效果如下图,我们可以知道目前程序已经占用了10
个CPU
核,属于比较高的CPU
占用率了。
2. top命令查看具体的进程内部的线程情况
接下来,我们使用以下命令访问对应的进程内部,查看是哪个线程占用了CPU
资源,如下:
top -H -p 24544
结果如下图:
我们可以从上图知道已经有10
个线程的CPU
占用率都达到了96%
。我们随机抽取一个线程,这里我们选取pid
为24937
的线程,并转换为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.invalidMap
是HashMap
对象,这是非线程安全类。在每次调用XssFilter.invalidMap
进行遍历的时候,如果刚好有其他线程进行了初始化,就会出现死循环的情况。在高并发的情况下,这种死循环情况的发生率就会很高了。所以项目在线上跑的时候,一般在高峰期就会出现这种情况,导致了CPU
飙高,进而导致项目不可访问。
解决方案
既然知道是HashMap
的死循环问题,那对HashMap
的初始化进行加锁即可。咨询了原开发人员,这个初始化一次即可。我这里提供一种解决方式,使用双重检查锁:
if (null == invalidMap) {
synchronized (invalidMap) {
if (null == invalidMap) {
// 初始化invalidMap
}
}
}
这样只需要初始化一次就可以,不会出现重复初始化。
结果
更新了补丁之后,目前项目运行正常。问题得到解决!!!
总结
编写代码的时候,还得多思考,多考虑高效和安全。本篇博文主要是讲述了整个解决过程的思路,一般按照这种思路,基本可以解决很多问题了。
随缘求赞
如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以点击关注
可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!