Java内存泄漏、CPU飙升排查

在Java应用开发中,内存泄漏和CPU飙升是两类高频出现的生产问题,也是常见的面试问题。这里通过一些demo进行实践。

内存泄漏

java 复制代码
private static List<byte[]> leakList = new ArrayList<>();

@GetMapping("/memory/leak")
public void test2() {
    try {
        while (true) {
            // 分配1MB的内存块
            byte[] block = new byte[1024 * 1024];
            leakList.add(block);

            // 每隔100毫秒分配一次,模拟内存不断积累
            Thread.sleep(100);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
shell 复制代码
java -jar -Xms256m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/wx/workspace/app.hprof test.jar


jstat -gcutil <pid> 1000  # 观察Old区使用率持续上涨

-XX:+HeapDumpOnOutOfMemoryError: 在发生 OutOfMemoryError 时自动生成堆转储文件(Heap Dump) -XX:HeapDumpPath: 指定堆转储文件的保存位置,可以使用工具(如 MAT、JProfiler 等)打开和分析

可以通过jmap命令生成hprof报告

shell 复制代码
jmap -dump:live,format=b,file=heap_dump.bin <pid>

# 查看Java进程
jps -l
jcmd
ps -ef | grep java

使用JProfiler打开*.hprof文件,查看最大内存占有的数据类型

点击目标数据类型,选择incoming references

  • incoming references:查看目标数据类型被哪些对象引用了
  • outgoing references:查看目标数据类型引用了哪些对象

找到泄漏对象 LeakedObject由于被静态集合引用而无法被垃圾回收,从而确定位置

CPU飙升

java 复制代码
@GetMapping("/cpu")
public void test3() {
    CompletableFuture<Void> t1 = CompletableFuture.supplyAsync(() -> {
            while (true) {
                // 密集计算,无退出条件
                double result = 0;
                for (int i = 0; i < 100000; i++) {
                    result += Math.sqrt(i) * Math.tan(i);
                }
            }
        }, threadPoolExecutor);

        CompletableFuture<Void> t2 = CompletableFuture.supplyAsync(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    System.out.println("正常业务运行中...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, threadPoolExecutor);
        CompletableFuture.allOf(t1, t2).join();
}
  1. 定位Java进程,top -c
  2. 查看线程级别CPU占用,top -Hp <PID>
  3. 抓去线程快照,jstack <PID> > thread.txt
  4. 线程ID转换printf "%x\n" <线程ID>
  5. 进行分析
txt 复制代码
"WXW-Thread-1" #35 daemon prio=5 os_prio=31 cpu=150071.37ms elapsed=150.75s tid=0x00007fdfb58fea00 nid=0x7207 runnable  [0x0000700006795000]
   java.lang.Thread.State: RUNNABLE
	at com.example.controller.TestThreadController.lambda$test3$2(TestThreadController.java:94)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(java.base@17.0.13/CompletableFuture.java:1768)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@17.0.13/ThreadPoolExecutor.java:1136)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@17.0.13/ThreadPoolExecutor.java:635)
	at java.lang.Thread.run(java.base@17.0.13/Thread.java:840)

通过日志查找问题所在

使用JProfiler分析CPU视图,定位异常线程和代码

内存结构

JVM(Java虚拟机)的内存结构是其运行时数据区域的核心组成部分,用于管理程序执行过程中的内存分配和回收

程序计数器

作用

记录当前线程执行的位置(字节码指令地址)

特性
  1. 线程私有,每个线程独立存储
  2. 唯一不会发生 OutOfMemoryError 的区域

虚拟机栈

作用

存储方法调用栈帧(每个方法对应一个栈帧),管理局部变量、操作数栈、动态链接和方法返回地址

栈帧结构
  • 局部变量表:存放方法参数和方法内定义的局部变量(基本类型和对象引用)
  • 操作数栈:执行自己饿吗指令的临时操作数存储区
  • 动态链接:指向运行时常量池中该方法的符号引用
  • 返回地址:方法退出后需要返回的位置
特点
  1. 线程私有
  2. 可能抛出的异常
    • StackOverflowError:栈深度超过限制(无限递归)
    • OutOfMemoryError:扩展栈是无法申请足够内存

本地方法栈

作用

为Native方法提供服务

特性

线程私有

方法区

作用

存储类信息、常量、静态变量、即时编译器编译后的代码,包含运行时常量池,存放编译期生成的字面量、符号引用及运行时添加的常量

特性
  1. 线程共享
  2. 可能抛出OutOfMemoryError

堆是Java应用程序最重要的一个内存结构

作用

存放所有对象实例和数组(通过 new 关键字创建的对象)

特性
  1. 线程共享
  2. 可能抛出OutOfMemoryError
  3. 通过 -Xmx-Xms 设置最大和初始堆大小,最好是设置一致
堆内存划分
  1. 新生代
    • Eden区:对象初次分配的区域
    • Survivor区:存放经过Minor GC后存活的对象
  2. 老年代:存放长期存活的对象(经过多次GC未被回收)
  3. 老年代:新生代=2:1,Eden区:Survivor0区:Survivor1区=8:1:1
相关推荐
上进小菜猪11 分钟前
基于 YOLOv8 的智能杂草检测识别实战 [目标检测完整源码]
后端
韩师傅1 小时前
前端开发消亡史:AI也无法掩盖没有设计创造力的真相
前端·人工智能·后端
栈与堆2 小时前
LeetCode-1-两数之和
java·数据结构·后端·python·算法·leetcode·rust
superman超哥2 小时前
双端迭代器(DoubleEndedIterator):Rust双向遍历的优雅实现
开发语言·后端·rust·双端迭代器·rust双向遍历
1二山似2 小时前
crmeb多商户启动swoole时报‘加密文件丢失’
后端·swoole
马卡巴卡2 小时前
Java CompletableFuture 接口与原理详解
后端
神奇小汤圆2 小时前
Java线程协作工具:CountDownLatch 、CyclicBarrier、Phaser、Semaphore 、Exchanger
后端
gelald2 小时前
ReentrantLock 学习笔记
java·后端
计算机学姐2 小时前
基于SpringBoot的校园资源共享系统【个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·mysql·spring·信息可视化
J_liaty3 小时前
RabbitMQ面试题终极指南
开发语言·后端·面试·rabbitmq