文章目录
- 启动一个Java应用模拟CPU飙高
- top 命令查询CPU占用率高的Java应用
- 分析该进程下占用CPU高的线程
- 将线程PID转换为16进制
- jstack 跟踪线程的调用栈
- 查看源码
jstack 介绍
jstack 是 JDK 提供的一个命令行工具,用于生成 Java 进程的线程快照。
线程快照包含了 Java 进程中所有线程的状态信息,如线程的名称、线程的状态(RUNNABLE、WAITING、BLOCKED 等)以及线程的调用栈。
通过分析 jstack 生成的线程快照,可以帮助您诊断诸如死锁、线程阻塞、CPU 使用率过高等与线程相关的问题。
启动一个Java应用模拟CPU飙高
写了一个普通Java应用模拟CPU飙高,将它启动起来
top 命令查询CPU占用率高的Java应用
输入top 命令进入top命令界面后,按大写字母 P
将根据CPU占用率排序, 按大写字母M
将根据内存占用率排序
top
查找CPU占用高的进程,复制进程PID 我这里是 461655
分析该进程下占用CPU高的线程
top -Hp {PID} 命令查看进程下的线程
top -Hp 461656
查找CPU占用高的线程,复制线程程PID 我这里是 461656
将线程PID转换为16进制
使用 printf “0x%x” {PID} 命令转换16进制
printf "0x%x" 461656
转为16进制后 0x70b58
jstack 跟踪线程的调用栈
jstack 是JDK提供的命令行工具,如果你配置了环境变量可以不用写全路径,没有环境变量就要加上你的JDK路径
# jstack 进程PID # |grep 0x70b58 过滤出该线程相关调用栈信息 # -A 50 输出后50行 /usr/local/jdk1.8.0_301/bin/jstack 461655 |grep 0x70b58 -A 50
以下输出调用栈中,可以看到在App.java中main方法第10行调用了线程就一直处于 java.lang.Thread.State: RUNNABLE
执行状态
查看源码
根据调用栈信息查看源码,原来代码中在计算圆周率后800万位。非常消耗CPU资源。
App.java
文件内容
package org.github.zuuyao;import java.math.BigDecimal;import java.math.RoundingMode;public class App { public static void main(String[] args) { System.out.println("calculatePi!"); // 计算圆周率精确到小数点八百万位 BigDecimal bigDecimal = calculatePi(8000000); System.out.println("pi Value : " + bigDecimal.toString()); } /** * 模拟CPU飙高 */ public static void simulation() { while (true) { // 什么都不执行,一直死循环。占用大量CPU资源 } } /** * 计算圆周率 * * @param decimalPlaces 圆周率小数点位数 * @return 计算结果 */ public static BigDecimal calculatePi(int decimalPlaces) { BigDecimal pi = BigDecimal.ZERO; BigDecimal sixteen = BigDecimal.valueOf(16); BigDecimal one = BigDecimal.ONE; for (int k = 0; k <= decimalPlaces; k++) { BigDecimal kBig = BigDecimal.valueOf(k); BigDecimal term = one.divide(sixteen.pow(k), decimalPlaces + 10, RoundingMode.HALF_UP); term = term.multiply( BigDecimal.valueOf(4) .divide(BigDecimal.valueOf(8 * k + 1), decimalPlaces + 10, RoundingMode.HALF_UP) .subtract(BigDecimal.valueOf(2) .divide(BigDecimal.valueOf(8 * k + 4), decimalPlaces + 10, RoundingMode.HALF_UP)) .subtract(BigDecimal.valueOf(1) .divide(BigDecimal.valueOf(8 * k + 5), decimalPlaces + 10, RoundingMode.HALF_UP)) .subtract(BigDecimal.valueOf(1) .divide(BigDecimal.valueOf(8 * k + 6), decimalPlaces + 10, RoundingMode.HALF_UP)) ); pi = pi.add(term); } return pi.setScale(decimalPlaces, RoundingMode.HALF_UP); }}
pom.xml
文件内容
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.github.zuuyao</groupId> <artifactId>troubleshooting-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>troubleshooting-demo</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> </dependencies> <build> <finalName>${artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <!--主启动类--> <mainClass>org.github.zuuyao.App</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build></project>