三步排查服务器中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>



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。