JVM CPU飙升问题

排查线上 java 进程CPU 飙升的问题


背景
某天晚上突然在工作群里看到服务响应变慢,于是急忙登录服务器看一下应用状态。如下图应用进程的状态一直徘徊在100%左右,但是一个台机器的服务cpu占用率极低。
在这里插入图片描述

根据网上资料
https://blog.csdn.net/qq_33404395/article/details/86242263?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

经过一番折腾最后定位到问题的原因,在极端的情况下系统陷入了死循环,问题伪代码如下

int i = 0;
while(i < 10){Integer result = xxxx; //执行业务代码,获取返回结果if(result != null){i ++;}
}

至此问题已经很明显,由于业务迭代变更,执行业务代码有可能变成null,所以陷入了死循环。

以下是自己在本机上写了个简单的demo,做出的一些总结。代码写了2个线程,其中一个线程陷入死循环状态。 由于本人是mac电脑 无法使用 top -H的命令(google了很久没找到对应的命令,无法定位进程里面的线程ID),因此使用docker作为虚拟机进行测试

package com.andy.jdk8.pool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/*** 模拟 cpu 飙升 test 类*/
public class CpuTest {public static void main(String[] args) {boolean isTrue = true;ExecutorService executor = Executors.newFixedThreadPool(2);executor.execute(new Runnable() {@Overridepublic void run() {while(true){System.out.println("dead loop");}}});executor.execute(new Runnable() {@Overridepublic void run() {for(int i = 0;i < 100000;i++){try {System.out.println("sleep loop");TimeUnit.SECONDS.sleep(2);}catch (Exception e){e.printStackTrace();}}}});}
}

步骤如下:

1、运行容器,将本机的class文件挂载到docker容器的/data目录下
docker run -itd --name java-cpu -v /Users/andy/tool/structure/structure/java/target/classes:/data java /bin/bash
2、进入容器,启动应用
docker exec -it java-cpu /bin/bash
cd /data
nohup java com.andy.jdk8.pool.CpuTest &
nohup 命令将程序作为后台进程运行
3、运行jcmd 命令,查看当前机器有多少java进行运行,如下图,前面的125就是进程id

在这里插入图片描述

4、找到进程中 占用资源率最高的线程 输入 top 125 ,然后按住 shift + h

在这里插入图片描述

4、可以看出140 这个线程ID,占用cpu的资源比较高,并将之转换成16进制
printf "%x\n" 140

在这里插入图片描述

5、定位线程代码,查看堆栈信息
jstack 125 |grep 8c -A 30
很明显问题出现在程序的第19行

在这里插入图片描述
6、我将排查的步骤写成了一个shell 脚本,以后直接运行就可以了。执行脚本的时候 代码应用名称,该脚本会查找应用进程里面占用资源cpu资源最高的线程堆栈,并输出到日志文件

pid=$(jcmd | grep $1 | awk '{print $1}')
echo "java process pid = $pid"threadid=$(top -Hp $pid -d 2 -n 1 -b | awk 'NR==8{print $1}')threadid0x=$(printf "%x\n" $threadid)jstack $pid |grep $threadid0x -A 30 > log.txtecho "execute success"

7、将文件内容名称成test.sh,执行 ./test.sh CpuTest . 执行的结果跟上面一致


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部