三步排查服务器中Java应用CPU飙高
ZuuuuYao 2024-10-21 17:37:03 阅读 80
文章目录
启动一个Java应用模拟CPU飙高top 命令查询CPU占用率高的Java应用分析该进程下占用CPU高的线程将线程PID转换为16进制jstack 跟踪线程的调用栈查看源码
<code>jstack 介绍
jstack 是 JDK 提供的一个命令行工具,用于生成 Java 进程的线程快照。
线程快照包含了 Java 进程中所有线程的状态信息,如线程的名称、线程的状态(RUNNABLE、WAITING、BLOCKED 等)以及线程的调用栈。
通过分析 jstack 生成的线程快照,可以帮助您诊断诸如死锁、线程阻塞、CPU 使用率过高等与线程相关的问题。
启动一个Java应用模拟CPU飙高
写了一个普通Java应用模拟CPU飙高,将它启动起来
top 命令查询CPU占用率高的Java应用
输入top 命令进入top命令界面后,按<code>大写字母 P将根据CPU占用率排序, 按大写字母M
将根据内存占用率排序
top
查找CPU占用高的进程,复制进程PID 我这里是 461655
分析该进程下占用CPU高的线程
top -Hp {PID} 命令查看进程下的线程
<code> top -Hp 461656
查找CPU占用高的线程,复制线程程PID 我这里是 461656
将线程PID转换为16进制
使用 printf “0x%x” {PID} 命令转换16进制
<code> printf "0x%x" 461656
转为16进制后 0x70b58
jstack 跟踪线程的调用栈
jstack 是JDK提供的命令行工具,如果你配置了环境变量可以不用写全路径,没有环境变量就要加上你的JDK路径
<code> # 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资源。
<code>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"code>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">code>
<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>
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。