应用--01--CPU飙升怎么处理?

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


CPU 飙升解决思路和方法论

在这里插入图片描述
使用jstack 解决 CPU 100%问题,在方法论上要用到的两个核心命令

  • top 命令查看TOP N线程,
  • jstack命令查看堆栈信息

1.确定Java进程ID

在这里插入图片描述

首先,需要找到CPU占用高的Java进程的PID(进程ID)。可以使用 top 或 ps 命令来找到该进程。

top
# 或安装 htop(更直观)
htop

在这里插入图片描述

2 找到占用CPU高的线程ID

查看进程的线程状态

  • 使用 top 时按 H 显示线程,或通过 ps 查看
  • 记下这些线程的ID(nid),这些ID是十进制的。
ps -T -p <PID>  # 查看指定进程的线程

在这里插入图片描述

在这里插入图片描述

3 将线程ID转换为十六进制

jstack 输出的线程ID是十六进制的,因此需要将找到的高CPU使用率的线程ID转换为十六进制。可以使用 printf 命令:

printf "%x\n" <thread_id>

在这里插入图片描述

4. 使用 jstack 生成线程快照

使用 jstack 命令生成Java进程的线程快照:

jstack -l <PID> > thread_dump.txt

在这里插入图片描述

5 分析线程快照

在生成的 thread_dump.txt 文件中,查找转换后的十六进制线程ID。可以使用 grep 命令:

grep "0x<hex_thread_id>" thread_dump.txt -A 20

这将显示包含该线程ID的线程栈信息。分析这些线程栈,找到可能导致CPU高占用的代码

在这里插入图片描述

在这里插入图片描述

6.使用阿里开源Arthas性能监控工具

https://arthas.aliyun.com/doc/
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后

生产中如果出现 CPU 飙升100% 的情况

  • 先确定前一天或者最近是否有新版本发布或者依赖域的服务有新版本发布,有的话第一时间回滚。
  • 如果最近或很长一段时间都没有新版本发布,那就先申请紧急扩容,增加机器

最后才是通过文本的这一套套路排查具体的原因分析和解决方案

CPU飙升原因分析

CPU占用率突然飙升是技术人员常遇到的一个棘手问题,它是一个与具体技术无关的普遍挑战、
这个问题可以很简单,也可以相当复杂。

  • 有时候,只是一个死循环在作祟。

  • 有时候,是死锁导致的。

  • 有时候,代码中有不必要的同步块。

  • 有时候,是大量计算密集型任务在运行。

  • 有时候,是线程数过多引起的。

  • 有时候,是频繁的上下文切换。

  • 有时候,是内存不足的问题。

  • 有时候,是频繁的垃圾回收。

  • 有时候,是内存泄漏导致的。
    等等。

导致CPU占用率飙升的问题多种多样,不同系统中的不同场景,其原因可能各不相同。

cpu占用很高的3大类型,9大场景

在这里插入图片描述

1.业务类问题

在这里插入图片描述

1.1 死循环

死循环是指程序在特定条件下进入了一个无限循环,无法跳出,导致CPU资源被完全占用。

例如:我们有一段代码用来检查文件的更新状态,但由于逻辑错误,条件永远无法满足,结果程序进入了死循环。

while (true) {
    if (file.isUpdated()) {
        break;
    }
}

1.2 死锁

死锁是指两个或多个线程互相等待对方释放资源,导致所有线程都无法继续执行,CPU资源被消耗殆尽。

在这里插入图片描述
发生死锁后,就会存在忙等待或自旋锁等编程问题,从而导致 繁忙等待问题,从而导致 CPU 100%

1.3 不必要的代码块

一些冗余、不必要的代码块在运行时占用了大量的CPU资源。

例如,不需要的地方使用synchronized块。

public synchronized void unnecessarySync() {
    // 执行一些不需要同步的操作
}

在不需要的地方使用synchronized块,会导致线程竞争和上下文切换

2.并发类问题

2.1 大量计算密集型的任务

大量计算密集型任务在同一时间运行,会导致CPU资源被完全占用。

例如:在数据分析或科学计算中,多个计算密集型任务同时运行
在这里插入图片描述

大量定时任务同一时间执行

在这里插入图片描述

解决方案
  • 比如定时任务或批处理,可以考虑错峰执行,
  • 优化任务本身,比如分批次处理,减少单次负载。

2.2 大量并发线程

统中存在大量并发线程,线程切换频繁,导致CPU资源被大量消耗在上下文切换上

例如:Web服务器同时处理大量请求,每个请求都创建一个新线程

在这里插入图片描述

解决方案
  • 使用线程池来限制并发线程数量

2.3 大量的上下文切换

当系统中存在大量线程时,CPU在不同线程间频繁切换,导致性能下降

例如:一个程序中开启了数百个线程,每个线程都在不断进行I/O操作

for (int i = 0; i < 1000; i++) {
    new Thread(new IOHandler()).start();
}

线程是很宝贵的资源,开启线程一定要合理的控制线程数量

3.内存类问题

3.1 内存不足

当系统内存不足时,就会将磁盘存储作为虚拟内存使用,而虚拟内存的运行速度要慢得多

例如:直接一次性加载一个非常大的文件到内存中,导致内存不足

byte[] largeData = Files.readAllBytes(Paths.get("largeFile.txt"));

这种过度的分页和交换会导致 CPU 占用率居高不下,因为处理器需要花费更多时间来管理内存访问,而不是高效地执行进程。

解决方案:
  • 优化内存使用,采用流式处理避免一次性加载大文件
try (BufferedReader reader = Files.newBufferedReader(Paths.get("largeFile.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        // 处理每一行数据
    }
}

3.2 频繁GC

频繁的垃圾回收(GC)操作会占用大量CPU资源,导致性能下降。

例如:程序中频繁创建和销毁对象,导致GC频繁触发

for (int i = 0; i < 1000000; i++) {
    String temp = new String("temp" + i);
}
解决方案:
  • 优化对象创建和销毁,减少临时对象的生成。

3.3 内存泄漏

内存泄漏导致可用内存逐渐减少,最终触发频繁的GC操作,占用大量CPU资源

例如:某个数据结构中不断添加对象,却从未删除,导致内存泄漏

List<Object> list = new ArrayList<>();
while (true) {
    list.add(new Object());
}
解决方案:
  • 定期清理不再使用的对象,使用合适的数据结
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值