人生若只如初见

WXY

Java进程CPU占用率过高分析定位

2022-08-19

一、场景描述

在实际应用场景中,JAVA 进程导致宿主机 CPU 使用率高的情况很常见,可能导致的原因很多:主机配置过低、代码质量低等;通常处于 bug 修复或者性能优化的需求,需要定位耗费大量 CPU 时间的罪魁祸首,这里提供几种常见的定位排查手段。

二、可选排查方式

【方式一】命令行 + jstack

jstack 是 Java 进程内的线程堆栈信息的常用工具,具体使用如下:

  • 定位消耗 CPU 的进程 pid(按 P 排序):top -c
  • 可以将进程堆栈导出:jstack -l <pid> > jstack.txt,然后加载到本地客户端工具或者网页工具(如:heapdump)中进行分析
  • 也可以完全使用命令行分析,定位消耗 CPU 的具体线程及其堆栈:top -Hp <pid>;输入 P 按 CPU 使用率排序,记住线程 pid 并转化为 16 进制:printf ‘%x\n’ ,得到 16 进制的 nid-16;接着在 jstack 中找到对应堆栈信息:jstack -l <pid> | grep <nid-16> -C5 -color 或者 jstack -l <pid> | grep <nid-16>
  • 检查 JAVA 进程是否存在死锁:jstack -l -F <pid>

【方式二】Arthas

Arthas 是 Alibaba 开源的一个 Java 诊断工具,方便进行问题的定位和诊断,可以在线排查问题,无需重启;动态跟踪 Java 代码;实时监控 JVM 状态。

  • 下载 jar 包:curl -O https://alibaba.github.io/arthas/arthas-boot.jar
  • 使用和业务应用相同的用户运行调试命令(会进入专用控制台并自动识别 java 进程并提供序号列表供选择):java -jar arthas-boot.jar
  • 使用说明:
    • 输入help命令查看支持的选项,dashboard命令用于整体展示进程所有线程、内存、GC 等情况,通过thread的-n 5选项找出最忙的前 5 个线程、-b 选项找出阻塞其他线程的线程,再输入thread 查看详情,使用trace或者tt命令进行跟踪分析,输入stop退出。
    • profiler命令支持生成应用热点的火焰图,默认生成的是 cpu 的火焰图(即 event 为 cpu,可以用 –event 参数来指定,支持的 event 可以使用profiler list命令获取), 常规命令:
      启动采样:profiler start
      查看已获取的样本数:profiler getSamples
      查看采样状态:profiler status
      停止采样:profiler stop(支持通过–file指定保存的文件名、–format html指定输出为 html 格式,默认为 svg)
  • 火焰图分析说明:
    y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数
    x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多、即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的
    颜色没有特殊含义,因为火焰图表示的是 CPU 的繁忙程度,所以一般选择暖色调
    火焰图就是看顶层的哪个函数占据的宽度最大。只要有”平顶”(plateaus),就表示该函数可能存在性能问题

【方式三】show-busy-java-threads 脚本

下载安装包:wget --no-check-certificate https://github.com/oldratlee/useful-scripts/archive/release.zip
解压:unzip release.zip && cd useful-scripts-release
使用(找出指定 java 进程中最消耗 CPU 的线程(缺省 5 个),打印出其线程栈):./show-busy-java-threads -p <pid>