线上CPU猛增,该如何排查

258 阅读2分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战

我们可以通过Jstack找出占用cpu最高的线程的堆栈信息,下面来一步一步分析。

假设我们有一段死循环,不断执行方法调用,线程始终运行不释放就会导致CPU飙高,示例代码如下:

package com.lxl.jvm;
​
public class Math {
    public static int initData = 666;
    public static User user = new User();
    public User user1;
​
    public int compute() {
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }
​
    public static void main(String[] args) {
        Math math = new Math();
        while(true){
            math.compute();
​
        }
    }
}

第一步:运行代码,使用top命令查看cpu占用情况

image

如上,现在有一个java进程,cpu严重飙高了,接下来如何处理呢?

第二步:使用top -p 命令查看飙高进程

top -p 46518

image

我们看到了单独的46518这个线程的详细信息

第三步:按H,获取每个线程的内存情况

需要注意的是,这里的H是大写的H。

img

我们可以看出线程0和线程1线程号飙高。

第四步:找到内存和cpu占用最高的线程tid

通过上图我们看到占用cpu资源最高的线程有两个,线程号分别是4018362,4018363。我们一第一个为例说明,如何查询这个线程是哪个线程,以及这个线程的什么地方出现问题,导致cpu飙高。

第五步:将线程tid转化为十六进制

67187778是线程号为4013442的十六进制数。具体转换可以网上查询工具。

第六步:执行[ jstack 4018360|grep -A 10 67187778] 查询飙高线程的堆栈信息

接下来查询飙高线程的堆栈信息

 jstack 4013440|grep -A 10 67190882
  • 4013440:表示的是进程号
  • 67187778: 表示的是线程号对应的十六进制数

通过这个方式可以查询到这个线程对应的堆栈信息

img

从这里我们可以看出有问题的线程id是0x4cd0, 哪一句代码有问题呢,Math类的22行。

第七步:查看对应的堆栈信息找出可能存在问题的代码

上述方法定位问题已经很精确了,接下来就是区代码里排查为什么会有问题了。

备注:上面的进程id可能没有对应上,在测试的时候,需要写对进程id和线程id