“Java 进程 CPU 使用率高”的解决思路是什么?

通常我们所说的 CPU 使用率过高,这里面其实隐含着一个用来比较高与低的基准值,比如 JVM 在峰值负载下的平均 CPU 利用率为 40%,如果 CPU 使用率飙到 80% 就可以被认为是不正常的。

典型的 JVM 进程包含多个 Java 线程,其中一些在等待工作,另一些则正在执行任务。在单个 Java 程序的情况下,线程数可以非常低,而对于处理大量并发事务的互联网后台来说,线程数可能会比较高。

对于 CPU 的问题,最重要的是要找到是哪些线程在消耗 CPU,通过线程栈定位到问题代码;如果没有找到个别线程的 CPU 使用率特别高,我们要怀疑到是不是线程上下文切换导致了 CPU 使用率过高。下面我们通过一个实例来学习 CPU 问题定位的过程。

定位高 CPU 使用率的线程和代码

  1. 写一个模拟程序来模拟 CPU 使用率过高的问题,这个程序会在线程池中创建 4096 个线程。代码如下:
@SpringBootApplication
@EnableScheduling
public class DemoApplication {// 创建线程池,其中有 4096 个线程。private ExecutorService executor = Executors.newFixedThreadPool(4096);// 全局变量,访问它需要加锁。private int count;// 以固定的速率向线程池中加入任务@Scheduled(fixedRate = 10)public void lockContention() {IntStream.range(0, 1000000).forEach(i -> executor.submit(this::incrementSync));}// 具体任务,就是将 count 数加一private synchronized void incrementSync() {count = (count + 1) % 10000000;}public static void main(String[] args) {springApplication.run(DemoApplication.class, args);}
}
  1. 在 Linux 环境下启动程序:
java -Xss256k -jar demo-0.0.1-SNAPSHOT.jar

请注意,这里我将线程栈大小指定为 256KB。对于测试程序来说,操作系统默认值 8192KB 过大,因为我们需要创建 4096 个线程。

  1. 使用 top 命令,我们看到 Java 进程的 CPU 使用率达到了 262.3%,注意到进程 ID 是 4361。
  2. 接着我们用更精细化的 top 命令查看这个 Java 进程中各线程使用 CPU 的情况:
#top -H -p 4361


从图上我们可以看到,有个叫“scheduling-1”的线程占用了较多的 CPU,达到了 42.5%。因此下一步我们要找出这个线程在做什么事情。

  1. 为了找出线程在做什么事情,我们需要用 jstack 命令生成线程快照,具体方法是:
jstack 4361

jstack 的输出比较大,你可以将输出写入文件:

jstack 4361 > 4361.log

然后我们打开 4361.log,定位到第 4 步中找到的名为“scheduling-1”的线程,发现它的线程栈如下:

从线程栈中我们看到了AbstractExecutorService.submit这个函数调用,说明它是 Spring Boot 启动的周期性任务线程,向线程池中提交任务,这个线程消耗了大量 CPU。

进一步分析上下文切换开销

死循环。但是对于这个实例的问题,你是否发现这样一个情况:Java 进程占用的 CPU 是 262.3%, 而

“scheduling-1”线程只占用了 42.5% 的 CPU,那还有将近 220% 的 CPU 被谁占用了呢?

不知道你注意到没有,我们在第 4 步用top -H -p 4361命令看到的线程列表中还有许多名为“pool-1-

thread-x”的线程,它们单个的 CPU 使用率不高,但是似乎数量比较多。你可能已经猜到,这些就是线程

池中干活的线程。那剩下的 220% 的 CPU 是不是被这些线程消耗了呢?

要弄清楚这个问题,我们还需要看 jstack 的输出结果,主要是看这些线程池中的线程是不是真的在干

活,还是在“休息”呢?

通过上面的图我们发现这些“pool-1-thread-x”线程基本都处于 WAITING 的状态,那什么是 WAITING 状态呢?或者说 Java 线程都有哪些状态呢?你可以通过下面的图来理解一下:


从图上我们看到“Blocking”和“Waiting”是两个不同的状态,我们要注意它们的区别:

  • Blocking 指的是一个线程因为等待临界区的锁(Lock 或者 synchronized 关键字)而被阻塞的状态,请你注意的是处于这个状态的线程还没有拿到锁。
  • Waiting 指的是一个线程拿到了锁,但是需要等待其他线程执行某些操作。比如调用了 Object.wait、Thread.join 或者 LockSupport.park 方法时,进入 Waiting 状态。前提是这个线程已经拿到锁了,并且在进入 Waiting 状态前,操作系统层面会自动释放锁,当等待条件满足,外部调用了 Object.notify 或者 LockSupport.unpark 方法,线程会重新竞争锁,成功获得锁后才能进入到 Runnable 状态继续执行。

回到我们的“pool-1-thread-x”线程,这些线程都处在“Waiting”状态,从线程栈我们看到,这些线程“等待”在 getTask 方法调用上,线程尝试从线程池的队列中取任务,但是队列为空,所以通过 LockSupport.park 调用进到了“Waiting”状态。那“pool-1-thread-x”线程有多少个呢?通过下面这个命令来统计一下,结果是 4096,正好跟线程池中的线程数相等。

你可能好奇了,那剩下的 220% 的 CPU 到底被谁消耗了呢?分析到这里,我们应该怀疑 CPU 的上下文切换开销了,因为我们看到 Java 进程中的线程数比较多。下面我们通过 vmstat 命令来查看一下操作系统层面的线程上下文切换活动:

如果你还不太熟悉 vmstat,可以在这里学习如何使用 vmstat 和查看结果。其中 cs 那一栏表示线程上下文切换次数,in 表示 CPU 中断次数,我们发现这两个数字非常高,基本证实了我们的猜测,线程上下文切切换消耗了大量 CPU。那么问题来了,具体是哪个进程导致的呢?

我们停止 Spring Boot 测试程序,再次运行 vmstat 命令,会看到 in 和 cs 都大幅下降了,这样就证实了引起线程上下文切换开销的 Java 进程正是 4361。

Tomcat进程占用CPU过高怎么办?相关推荐

  1. memcached 如果进程占用cpu很高

    memcached 如果进程占用cpu很高 一客户占用到了 25% 把mencache内存大小从32m 改成256m 后 memcached 基本占用cpu 是0 可能分配的内存不够用了  大量的新缓 ...

  2. linux下查找java进程占用CPU过高原因

    linux下查找java进程占用CPU过高原因 1. 查找进程 top查看进程占用资源情况 明显看出java的两个进程22714,12406占用过高cpu. 2.查找线程 使用top -H -p &l ...

  3. vs code1.61.1 任务管理器里出现2个rg进程占用cpu很高电脑运行卡

    环景: win10专业版 vs code v.1.61.1 问题描述: 任务管理器里出现2个rg进程占用cpu很高,电脑卡 解决方案: vs code软件里打开文件->首选项->设置搜se ...

  4. redis进程占用CPU很高-达到100

    问题说明: 监控发现,redis进程占用CPU很高-达到100%.并且会有2个redis进程.如下图: 分析了一下,因为redis在持久化保存的时候,会fork出一个进程来.仔细观察进程号PID,会发 ...

  5. Microsoft Compatibility Telemetry进程占用CPU过高如何解决?

    知识点分析: Win10使用中,发现Microsoft Compatibility Telemetry进程占用CPU过高,导致机器卡顿. Microsoft Compatibility Telemet ...

  6. Ubuntu16.04.06 LTS -bash 进程占用cpu很高,中了挖矿病毒

    环景: Ubuntu16.04.06 LTS 问题描述: -bash 进程占用cpu很高,别的进程开启运行过后就被它killed,-bash一直占用50%的CPU,服务器被拉的嗷嗷叫 解决方案: 1. ...

  7. linux php cpu,查找linux下进程占用CPU过高的原因,以php-fpm为例

    很多时候,线上服务器的进程在某时间段内长时间占用CPU过高,为了优化,我们需要找出原因. 1.找出占用CPU最高的10个进程 ps aux | sort -k3nr | head -n 10 或查看占 ...

  8. 趣味编程故事|java进程占用cpu过高怎么办,别急我来帮你

    关注公众号"AI码师"领取2021最新面试资料一份 [主演] 运维小哥:小李 测试小姐姐:小红 开发人员:本色出演 [剧情] 在一个阳光明媚的清晨,原本还在睡梦中的我,被小李(运维 ...

  9. macos13发热严重(CMFSynAgent和sharingd两个进程占用cpu太高)

    在我的macos系统升级到ventura之后,发现电脑发热异常严重,掉电非常快,起初以为是电脑配置带不动了,然后发现我合上盖子后,有时候风扇还在转动.当我打开活动监视器之后有两个进程占用CPU特别大- ...

最新文章

  1. 消防信号二总线有没电压_消防的电源总线和二总线的区别,二总线是不是信号..._消防考试_帮考网...
  2. VMware vSphere 6.7配置最大更改
  3. 关于估时间的一些感想
  4. python学习 (二十九) range函数
  5. 邹欣对话图灵奖得主Jeffrey Ullman:数据库不会进入周期性的坏循环|《新程序员》...
  6. android windowsoftinputmode 状态栏冲突,android:windowSoftInputMode属性
  7. form的get与post方式的区别(转)
  8. android仿qq空间、微信朋友圈图片展示
  9. python代码模拟 手写字体
  10. 电脑文件备份到哪里最安全?
  11. 收集下载电影的好网站
  12. It is a distutils installed project and thus we cannot accurately determine which files belong to
  13. 阿里巴巴集团去IOE运动的思考与总结
  14. 用户留存分析学习整理
  15. FFmpeg基础库编程开发学习笔记——音频常见格式及字幕格式
  16. 20191009 3. 史上最全的USB-PD充电协议,包含PD协议波形图
  17. spring boot 配置Filter过滤器
  18. android入门之broadcast
  19. 51nod 1298 圆与三角形(几何知识)
  20. 旗舰计算机系统蓝图,【求助】求助大神给这些蓝图一个参考定价

热门文章

  1. 《有限与无限的游戏》第一章 世上至少有两种游戏:经典摘抄(3)
  2. 2022-02-17 WPF上位机 120-三菱PLC协议之读写方法流程解析
  3. 网页gis服务器,在局域网中搭建自己的gis服务器
  4. ASP.NET收银管理系统源码(CS架构)
  5. SDL入门教程(一):2、Visual C++ 下的安装与设置
  6. 51单片机(九)LED点阵屏
  7. 如何配置Maven镜像?
  8. 自己训练的Resnet部署(python版本)
  9. 「 每日一练,快乐水题 」953. 验证外星语词典
  10. 财务做账自动化生成系统