线上java进程CPU占用率太高问题排查
线上排查java进程占用cpu过高问题
一、创建springBoot项目
新建的项目需引入web依赖支持,方便我们通过http调用
pom.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.javapc</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>javapc</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 引入web依赖 -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
</dependencies>
<build>
<plugins>
<!-- springboot打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.javapc.demo.JavapcApplication</mainClass>
<!-- <skip>true</skip> -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
修改启动类
package com.javapc.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JavapcApplication {
public static void main(String[] args) {
SpringApplication.run(JavapcApplication.class, args);
int count = 9;
while(count < 10){
count = count >> 2 << 2;
System.out.println(count);
}
}
}
打包
将打好的demo-0.0.1-SNAPSHOT.jar
上传到虚拟机并启动。简单吧,不再细说。
二、CPU占用过高问题排查
启动demo-0.0.1-SNAPSHOT.jar
java -jar demo-0.0.1-SNAPSHOT.jar &
启动后使用top -c
命令显示运行中的进程列表信息,找到 cpu 占有率最高的 java 进程号。
通过shift + p 通过 cpu 占用率进行排序,可知44974
的java进程占用 cpu 最高。
下面使用 jstack
命令生成 Java 进程中所有线程的快照
jstack -l 44974 > /root/44974.stack
扩展
问题:
在执行命令时可能会报一下错误:
Unable to open socket file: target process not responding or HotSpot VM not loaded
分析:
Java进程启动时会自动创建 hsperfdata_$USER
目录,并生成 44974
文件, hsperfdata_$USER
目录默认会创建在 /tmp
目录下,如下图:
由于Linux一切皆文件的特性,也就是说一个Java进程实际上会对应到一个PID文件,stack命令依赖于进程的PID文件也就是44974
文件,报错这个是由于这个PID文件可能已经被系统给删除了。
那到底是被谁删掉的呢,当然是linux系统自己删的。
linux系统有个删除管理机制:系统每天会用tmpwatch命令检查并删除 /tmp 下超过240小时未访问过的文件和目录。
解决:
https://bxoon.blog.csdn.net/article/details/111881528
使用top -Hp pid
查看 java 进程中占用 cup 最高的线程,也可以通过shift + p 进行排序
top -Hp 44947
由上图可知是 44975
的进程 cpu 占用率最高,将 44975
十进制数转换为十六进制
[root@localhost ~]# printf "%x\n" 44975
afaf
进入/root
目录,打开刚通过 stack 命令生成的 44974.stack
文件,并在文件中搜索 afaf
到此定位到问题,就是JavapcApplication.java的第14
行
三、内存占用过高问题排查
使用 top -c
命令显示运行中的进程列表信息,通过 shift + m 按内存占用率进行排序
利用 jmap 生成堆转储快照
[root@localhost ~]# jmap -dump:format=b,file=/root/dumpheap_125280.hprof 125280
Dumping heap to /root/dumpheap_125280.hprof ...
Heap dump file created
将dumpheap_125280.hprof 125280文件下载到本地,然后装入“jvisualvm”工具中。
分析过程在jvisualvm分析内存溢出问题讲述过,如需阅读请跳转至该文查看。