[Java实战]Spring Boot服务CPU 100%问题排查:从定位到解决

news2025/3/18 6:09:27

Spring Boot服务CPU 100%问题排查:从定位到解决

1. 引言

当Spring Boot服务出现CPU占用率100%时,系统性能会急剧下降,甚至导致服务不可用。本文将通过真实代码案例,详细讲解如何快速定位问题根源,并提供解决方案。无论是死循环、线程阻塞还是资源泄漏,本文帮你一网打尽!

2. 问题现象

  • 服务器CPU使用率持续100%
  • 接口响应时间变长或超时
  • 通过监控工具(如Grafana、Arthas)发现异常线程

3. 排查步骤

3.1 编写测试代码

在这里插入图片描述

3.2 运行代码效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 定位高CPU进程

使用top命令快速找到占用CPU最高的Java进程:

top -c   # 显示完整命令,找到PID

终端输入命令:top -c,找到高cpu进程PID:420364

在这里插入图片描述

3.4 定位高CPU线程

通过top -Hp <PID>查看进程内线程的CPU使用情况,记录线程ID(需转换为十六进制):

#查找进程中的线程
top -Hp <PID>

top -Hp 420364
 # 假设线程ID为433127 → 69be7 输出为16进制

printf "%x\n" 433127 


[root@localhost java]# printf "%x\n" 433127 
69be7

终端输入命令:top -Hp 420364,定位高cpu线程:433127

线程ID转换为16进制:69be7

生成堆栈信息:jstack 420364 > stack.log 生成时PID:420364

通过堆栈信息分析:grep -A 20 ‘nid=0x69be7’ stack.log nid=0x69be7为线程id

根据信息对比原代码可找到问题

在这里插入图片描述

3.5分析线程堆栈

使用jstack捕获线程堆栈并分析:

#生成线程堆栈
jstack <PID> > stack.log

jstack 420364 > stack.log
 # 搜索特定线程
grep -A 20 'nid=0x69be7' stack.log 

在这里插入图片描述

在这里插入图片描述

排查结果及源代码问题对比:类32行运行结果导致cpu 100%

在这里插入图片描述

3.5 Arthas 工具定位

以上是根据Java自带的jstack 工具定位, Arthas 工具也能定位排查。定位思路和上面步骤一致

#安装下载启动
curl -O https://arthas.aliyun.com/arthas-boot.jar

java -jar arthas-boot.jar

启动选择需要定位项目:2

在这里插入图片描述

直接输入查看高cpu线程: thread

在这里插入图片描述

查看堆栈信息找到代码问题: thread 29 (线程ID)

在这里插入图片描述

如果想看实时面板信息: dashboard

在这里插入图片描述

4. 常见原因与代码示例

4.1 死循环(While循环未正确退出)

问题代码

@Service
public class CpuProblemController {
    public void deadLoop() {
        while (true) {  // 无条件退出,导致死循环
            // 业务逻辑(如未正确更新循环条件)
        }
    }
}

解决方案

@Service
public class CpuProblemController {
    private volatile boolean running = true;  // 添加退出标志
    
    public void deadLoop() {
        while (running) {  // 通过控制running变量退出循环
            // 业务逻辑
        }
    }
    
    @PreDestroy
    public void stop() {
        running = false;  // 服务关闭时触发退出
    }
}

测试完整类:

package com.example.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@RestController
@RequestMapping("/pro")
public class CpuProblemController {
    // 添加退出标志
    private volatile boolean running = true;

    // 创建线程池
    private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    /**
     * 死循环:模拟 CPU 占满
     */
    @PostMapping("/deadLoop")
    public void deadLoop() {
        // 启动多个线程,每个线程执行死循环
        for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
            executorService.submit(() -> {
                while (running) {
                    // 死循环,模拟高 CPU 使用率
                    System.out.println("=======死循环=========");
                    // 加入计算密集型任务
                    for (int j = 0; j < 1000000; j++) {
                        Math.sin(j); // 计算密集型操作
                    }
                }
            });
        }
    }

    @PreDestroy
    public void stop() {
        // 服务关闭时触发退出
        running = false;
        executorService.shutdownNow(); // 关闭线程池
    }
}

4.2 不合理递归(栈溢出与CPU飙升)

问题代码

public class RecursionController {
    public int faultyRecursion(int n) {
        return n + faultyRecursion(n - 1);  // 无终止条件 → 无限递归
    }
}

解决方案

public class RecursionController {
    public int safeRecursion(int n) {
        if (n <= 0) {  // 添加递归终止条件
            return 0;
        }
        return n + safeRecursion(n - 1);
    }
}

4.3 线程池未正确关闭(资源泄漏)

问题代码

@RestController
public class ThreadController {
    private ExecutorService executor = Executors.newFixedThreadPool(10);

    @GetMapping("/task")
    public String submitTask() {
        executor.submit(() -> {
            while (true) {  // 线程池任务未终止
                // 长时间运行的任务
            }
        });
        return "Task submitted!";
    }
    
    // 未重写destroy方法关闭线程池 → 线程泄漏
}

解决方案

@RestController
public class ThreadController {
    private ExecutorService executor = Executors.newFixedThreadPool(10);

    @GetMapping("/task")
    public String submitTask() {
        executor.submit(() -> {
            while (!Thread.currentThread().isInterrupted()) {  // 检查中断状态
                // 可中断的任务逻辑
            }
        });
        return "Task submitted!";
    }
    
    @PreDestroy
    public void shutdown() {
        executor.shutdownNow();  // 服务关闭时终止线程池
    }
}

4.4 锁竞争(线程阻塞与自旋)

问题代码

public class LockCompetitionController {
    private final Object lock = new Object();
    
    public void highCpuMethod() {
        synchronized (lock) {
            // 长时间持有锁(如复杂计算或IO操作)
            try {
                Thread.sleep(10000);  // 模拟耗时操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

解决方案

public class LockCompetitionDemo {
    private final Object lock = new Object();
    
    public void optimizedMethod() {
        // 缩小锁范围,只锁必要部分
        heavyCalculation();  // 将非线程安全操作移到锁外
        
        synchronized (lock) {
            // 仅保护共享资源
        }
    }
    
    private void heavyCalculation() {
        // 复杂计算逻辑
    }
}

4.5 频繁GC(内存泄漏导致CPU飙升)

问题代码

public class MemoryLeakDemo {
    private static List<byte[]> cache = new ArrayList<>();
    
    @GetMapping("/leak")
    public void leakMemory() {
        while (true) {
            cache.add(new byte[1024 * 1024]);  // 不断添加数据 → 触发Full GC
        }
    }
}

解决方案

public class MemoryLeakDemo {
    private static final int MAX_CACHE_SIZE = 100;
    private static List<byte[]> cache = new ArrayList<>();
    
    @GetMapping("/safe")
    public void safeMethod() {
        if (cache.size() >= MAX_CACHE_SIZE) {
            cache.clear();  // 定期清理缓存
        }
        cache.add(new byte[1024 * 1024]);
    }
}

5. 总结与预防

  1. 代码审查:重点关注循环、递归、线程池和锁的使用。
  2. 压测与监控:使用JMeter模拟高并发,通过Arthas实时监控CPU。
  3. 防御式编程:对递归添加终止条件,对循环添加超时机制。
  4. 工具辅助:利用jvisualvmasync-profiler进行性能分析。

希望这篇文章对你有所帮助!如果觉得不错,别忘了点赞收藏哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317041.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.6 极限存在准则

1.夹逼定理&#xff08;迫敛定理&#xff09; 1.1 数列型 1.1.1 准则 1.2 函数型 2. 两个重要极限

大华SDK协议在智联视频超融合平台中的接入方法

一. 大华SDK协议详解 &#xff08;一&#xff09;、大华SDK协议概述 大华SDK&#xff08;Software Development Kit&#xff09;协议是大华股份为开发者提供的一套软件开发工具包&#xff0c;旨在帮助开发者快速集成大华设备&#xff08;如摄像头、NVR、DVR等&#xff09;的功…

卓越的用户体验需要智能内容

摘要&#xff1a;这篇文章指出静态文档已无法满足现代用户的需求&#xff0c;而智能内容则是构建卓越用户体验的关键。文章从智能内容的定义、优势和实际应用等方面进行了详细阐述&#xff0c;并强调了企业应积极拥抱智能内容&#xff0c;以提升客户满意度、降低成本并创造新的…

【蓝桥杯】1124修建公路1(Kruskal算法)

思路 找到能够连通所有城市的最小树即可&#xff0c;可用Prim或Kruscal。 &#xff01;&#xff01;注意&#xff0c;m的范围是包括0的&#xff0c;可就是包含没有道路的情况&#xff0c;要单独输出0 code import os import sys# 输入 n,m map(int,input().split()) road …

传感云揭秘:边缘计算的革新力量

在当今快速发展的科技时代&#xff0c;传感云和边缘计算系统正逐渐成为人们关注的焦点。传感云作为物联网与云计算的结合体&#xff0c;通过虚拟化技术将物理节点转化为多个服务节点&#xff0c;为用户提供高效、便捷的服务。而边缘计算则是一种靠近数据源头或物端的网络边缘侧…

Bigemap Pro 的三种地图下载方式

地图下载通常是是最基础但也最重要的任务之一&#xff0c;无论是进行空间分析、制作专题地图&#xff0c;还是进行数据可视化&#xff0c;高质量的地图数据都是不可或缺的。Bigemap Pro提供了三种地图下载方式&#xff0c;分别适用于不同的场景和需求。无论是免费版用户还是专业…

Python直方图:从核密度估计到高维空间解析

一、直方图的核心原理与数学本质 数据分布的视觉解码器 直方图&#xff08;Histogram&#xff09;是数据科学家的"分布显微镜"&#xff0c;通过将连续数据划分为等宽区间&#xff08;Bin&#xff09;&#xff0c;统计各区间的频数/频率&#xff0c;用相邻矩形条直观…

0基础 | 恒流源专题

目录 tip1&#xff1a;低端反馈​编辑 tip2: 恒流源电路的设计注意事项 tip3&#xff1a;三极管输出恒定电流受运放输出电流控制 tip4&#xff1a;高端反馈 基本逻辑&#xff1a; 当负端Vref不输入电压时&#xff0c; 当负端Vref输入电压时 tip1&#xff1a;低端反馈 判…

Webpack 前端性能优化全攻略

文章目录 1. 性能优化全景图1.1 优化维度概览1.2 优化效果指标 2. 构建速度优化2.1 缓存策略2.2 并行处理2.3 减少构建范围 3. 输出质量优化3.1 代码分割3.2 Tree Shaking3.3 压缩优化 4. 运行时性能优化4.1 懒加载4.2 预加载4.3 资源优化 5. 高级优化策略5.1 持久化缓存5.2 模…

【YOLOv8】YOLOv8改进系列(7)----替换主干网络之LSKNet

主页&#xff1a;HABUO&#x1f341;主页&#xff1a;HABUO &#x1f341;YOLOv8入门改进专栏&#x1f341; &#x1f341;如果再也不能见到你&#xff0c;祝你早安&#xff0c;午安&#xff0c;晚安&#x1f341; 【YOLOv8改进系列】&#xff1a; 【YOLOv8】YOLOv8结构解读…

【LangChain】理论及应用实战(7):LCEL

文章目录 一、LCEL简介二、LCEL示例2.1 一个简单的示例2.2 RAG Search 三、LCEL下核心组件&#xff08;PromptLLM&#xff09;的实现3.1 单链结构3.2 使用Runnables来连接多链结构3.2.1 连接多链3.2.2 多链执行与结果合并3.2.3 查询SQL 3.3 自定义输出解析器 四、LCEL添加Memor…

ai本地化 部署常用Ollama软件

现在用最简单的方式介绍一下 Ollama 的作用和用法&#xff1a; Ollama 是什么&#xff1f; Ollama 是一个让你能在自己电脑上免费运行大型语言模型&#xff08;比如 Llama 3、Mistral 等&#xff09;的工具。 相当于你本地电脑上有一个类似 ChatGPT 的 AI&#xff0c;但完全…

vllm部署QwQ32B(Q4_K_M)

vllm部署QwQ32B(Q4_K_M) Ollama是一个轻量级的开源LLM推理框架&#xff0c;注重简单易用和本地部署&#xff0c;而VLLM是一个专注于高效推理的开源大型语言模型推理引擎&#xff0c;适合开发者在实际应用中集成和使用。两者的主要区别在于Ollama更注重为用户提供多种模型选择和…

企业内网监控软件的选型与应用:四款主流产品的深度剖析

在数字化办公的时代背景下&#xff0c;企业内部网络管理的重要性愈发显著。对于企业管理者而言&#xff0c;如何精准掌握员工工作状态&#xff0c;保障网络安全与工作效率&#xff0c;已成为亟待解决的关键问题。本文将深入剖析四款主流企业内网监控软件&#xff0c;探讨其功能…

Qt窗口控件之字体对话框QFontDialog

字体对话框QFontDialog QFontDialog 是 Qt 内置的字体对话框&#xff0c;用户能够在这里选择字体的样式、大小&#xff0c;设置加粗和下划线并将结果作为返回值返回。QFontDialog 最好使用其提供的静态函数实例化匿名对象&#xff0c;并获取返回值最为用户选择字体设置的结果。…

Qt QML实现视频帧提取

## 前言 视频帧率&#xff08;Frame Rate&#xff09;是指视频播放时每秒显示的画面帧数&#xff0c;通常用fps&#xff08;Frames Per Second&#xff09;来表示。视频是由一系列静止的图像帧组成的&#xff0c;而视频帧率则决定了这些图像帧在单位时间内播放的速度。较高的视…

在 Ubuntu 服务器上使用宝塔面板搭建博客

&#x1f4cc; 介绍 在本教程中&#xff0c;我们将介绍如何在 Ubuntu 服务器 上安装 宝塔面板&#xff0c;并使用 Nginx PHP MySQL 搭建一个博客&#xff08;如 WordPress&#xff09;。 主要步骤包括&#xff1a; 安装宝塔面板配置 Nginx PHP MySQL绑定域名与 SSL 证书…

有了大语言模型还需要 RAG 做什么

一、百炼平台简介 阿里云的百炼平台就像是一个超级智能的大厨房&#xff0c;专门为那些想要做出美味AI大餐的企业和个人厨师准备的。你不需要从头开始做每一道菜&#xff0c;因为这个厨房已经为你准备了很多预制食材&#xff08;预训练模型&#xff09;&#xff0c;你可以根据…

【从0到1搞懂大模型】RNN基础(4)

先说几个常用的可以下载数据集的地方 平台&#xff1a;kaggle&#xff08;https://www.kaggle.com/datasets&#xff09; 和鲸社区&#xff08;https://www.heywhale.com/home&#xff09; 阿里天池&#xff08;https://tianchi.aliyun.com/&#xff09; 其他&#xff1a;海量公…

【第K小数——可持久化权值线段树】

题目 代码 #include <bits/stdc.h> using namespace std;const int N 1e5 10;int a[N], b[N]; int n, m, len; int rt[N], idx; // idx 是点分配器struct node {int l, r;int s; } tr[N * 22];int getw(int x) {return lower_bound(b 1, b len 1, x) - b; }int bui…