使用jstack排查CPU飙升的问题记录

        最近,看到短视频传播了一个使用jstack来协助排查CPU飙升的案例。我也是比较感兴趣,参考了视频博主的流程,自己做了下对应案例的实战演练,在此,想做一下,针对相关问题模拟与排查演练的实战过程记录。

        案例中所使用的DEMO代码,我已经放到了以下的代码仓库中,有需要的同学,可以自行下载与学习演练。代码仓库地址:https://github.com/AlickLiubc/cpu-problems-demo

        在演练代码中,主要通过一段死循环,来模拟了系统CPU飙升的代码原因。

具体步骤:

步骤1:

将代码打成jar包并放置在Linux的系统运行环境中运行:

mvn clean package -DskipTests
nohup java -jar cpu-problems-demo-1.0-SNAPSHOT.jar > /dev/null 2> /dev/null &

步骤2:

通过浏览器打开与观察接口的问题现象,如下图所示,浏览器处于不断加载的过程中:

步骤3:

使用top命令,查看占用CPU比较高的进程ID(十进制),可以看到PID=16013的进程占用CPU很高。

top

步骤4:

进一步使用top命令查询占用CPU比较高的线程ID

top -H -p 16013

此时,可以得到占用CPU很高的线程ID(十进制),PID=16029。

步骤5:

将步骤4中得到的十进制的线程ID转换为十六进制值为0x3e9d:

printf "0x%x\n" 16029

步骤6:

结合以上步骤中得到的进程ID(十进制)与线程ID(十六进制),可以找到问题源头的相关代码信息:

jstack 16013 | grep 0x3e9d -A 20

<think>嗯,用户之前问过关于如何使用jstack下载的问题,现在他们想了解如何用top和jstack排查CPUJava进程。我需要确保回答结构清晰,分步骤解释,并且结合之前的指南内容。 首先,用户可能已经安装了JDK,所以可能不需要再重复安装步骤,但可能需要确认环境变量是否正确设置。接着,需要解释如何用top找到高CPUJava进程,然后使用jstack分析线程情况。 用户可能对Linux命令不太熟悉,所以步骤要详细,比如如何用top查看进程,如何转换线程模式,如何找到占用高的线程ID。然后,将线程ID转换为十六进制,以便在jstack输出中查找对应的堆栈信息。 另外,用户可能需要知道如何分析线程堆栈,识别问题代码,比如死循环、阻塞操作等。还要注意权限问题,可能需要sudo执行jstack。此外,可以推荐其他工具如jcmd或arthas作为补充,这部分在之前的回答里提到过,需要保持一致性。 需要避免使用复杂术语,用中文简单解释每个步骤的目的,例如为什么需要线程ID转换,如何通过堆栈定位代码。还要提醒常见问题,比如权限不足或者JDK路径问题,参考之前的问题解决部分。 最后,确保LaTeX格式正确,行内代码用反引号,独立代码块用三个反引号,但用户要求使用$...$和$$...$$,不过在这里可能主要是代码块,所以按之前的格式处理。检查是否有遗漏的步骤,比如是否需要多次抓取jstack快照对比,或者结合其他日志分析。 总结下来,回答应该分步骤,从定位进程到分析线程,再到定位代码,结合示例命令和输出,帮助用户逐步排查CPU问题。同时,注意与之前回答的衔接,比如环境变量配置和工具推荐,保持信息一致。</think>--- ### 分步排查CPUJava进程(结合`top`与`jstack`) --- #### **Step 1:定位高CPUJava进程** 使用`top`命令快速筛选目标进程: ```bash # 启动top后按以下键位操作 1️⃣ 输入大写`P`:按CPU使用率排序 2️⃣ 输入`c`:显示完整命令行(确认Java进程) 3️⃣ 输入`H`:切换到线程模式(查看具体线程) ``` *示例输出片段:* ``` PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1234 app 20 0 12.3g 2.1g 15m S 198.3 6.7 10:30.9 java -Xmx4g ... ``` --- #### **Step 2:获取问题线程的十进制PID** 在`top`线程模式下: - 记录CPU的线程PID(例如`5678`) - **关键操作**:将十进制PID转为十六进制(用于匹配jstack输出) ```bash # 使用printf快速转换 printf "%x\n" 5678 # 输出示例:162e ``` --- #### **Step 3:生成线程堆栈快照** 通过`jstack`导出线程状态(需JDK环境): ```bash # 抓取进程的快照(PID=1234) jstack 1234 > thread_dump.log # 若权限不足,添加用户参数 sudo -u <进程所属用户> jstack 1234 > thread_dump.log ``` --- #### **Step 4:关联CPU高负载线程** 在`thread_dump.log`中搜索十六进制线程ID(`nid=0x162e`): ```text "main" #1 prio=5 os_prio=0 tid=0x00007f4874009800 nid=0x162e runnable [0x00007f487d1fe000] java.lang.Thread.State: RUNNABLE at com.example.LoopService.infiniteLoop(LoopService.java:42) at com.example.Main.run(Main.java:15) ``` *关键字段解析*: - `nid=0x162e`:对应top中高CPU线程的十六进制PID - `Thread.State`:线程状态(RUNNABLE/BLOCKED等) - 堆栈调用链:定位到具体代码行(例如`LoopService.java:42`) --- #### **Step 5:典型问题代码模式** 通过线程状态快速判断问题类型: | 线程状态 | 常见问题场景 | 代码特征 | |-------------|-----------------------------|-----------------------------| | **RUNNABLE**| CPU密集型操作 | 死循环、复杂算法、未休眠的轮询 | | **BLOCKED** | 资源竞争 | synchronized锁竞争、数据库锁 | | **WAITING** | 线程挂起 | wait()/join()未唤醒、I/O阻塞 | --- ### 增强排查技巧 #### **技巧1:连续抓取快照对比** ```bash # 每隔2秒抓取3次快照(观察线程状态变化) for i in {1..3}; do jstack 1234 > dump_$i.log; sleep 2; done ``` #### **技巧2:结合`jstat`监控GC** ```bash # 检查GC是否频繁(间隔1秒,输出10次) jstat -gcutil 1234 1000 10 # 输出字段说明: S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 99.99 68.45 98.33 95.12 90.20 120 15.234 5 3.456 18.690 ``` *高`FGC`(Full GC次数)或`FGCT`(Full GC时间)可能引发CPU飙升* --- ### 替代方案推荐 #### **方案1:使用`jcmd`快速诊断** ```bash # 列出所有Java进程 jcmd -l # 生成线程转储(等效于jstack) jcmd 1234 Thread.print > thread_dump.log ``` #### **方案2:Arthas实时分析** ```bash # 启动Arthas并附加到进程 ./arthas-boot.jar 1234 # 执行线程CPU占比统计 thread -n 3 # 显示CPU最高的3个线程 ``` --- ### 注意事项 1. **权限问题**:生产环境操作需获得授权,避免影响服务 2. **快照时间**:尽量在CPU高峰时抓取快照 3. **混合模式**:若涉及JNI代码,添加`-m`参数捕获本地栈 ```bash jstack -m 1234 > native_stack.log ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值