当前位置: 首页 > news >正文

java堆内存泄漏利用内存分析工具(Memory Analyzer Tool,MAT)分析

java堆内存泄漏利用内存分析工具(Memory Analyzer Tool,MAT)分析

  • java堆内存泄漏利用内存分析工具(Memory Analyzer Tool,MAT)分析
    • 1. 前置准备
    • 2. 编译代码
    • 3. 在 Windows 上编译
    • 4. 在 Windows 上运行 (关键步骤)
    • 5. 观察现象
    • 6. 如何验证是“频繁 FGC”导致的?
    • 7. 解压配置java运行环境启动mat分析程序

java堆内存泄漏利用内存分析工具(Memory Analyzer Tool,MAT)分析

可以,完全可以在 Windows 上执行。
生成 .hprof 文件、运行导致频繁 FGC 的 Java 代码以及使用 jmap/jcmd 等工具,在 Windows 上的操作逻辑与 Linux/macOS 基本一致,只是命令格式和路径分隔符略有不同。
以下是在 Windows 环境下操作的完整指南:

1. 前置准备

确保您的 Windows 机器上已安装 JDK (不仅仅是 JRE),并且配置了环境变量 JAVA_HOME 和 PATH。
验证方法:打开 CMD 或 PowerShell,输入 java -version 和 javac -version
最简单且稳定的方法是:不断创建大对象并持有它们,强制填满老年代(Old Generation)。当老年代空间不足时,JVM 会频繁触发 Full GC 尝试清理,如果清理不掉(因为对象都被引用着),最终会导致 OOM 并生成 .hprof 文件。
以下是纯原生 Java 代码及 Windows 执行步骤:

2. 编译代码

编写代码 (无需任何第三方 jar 包)
新建一个文件 FgcGenerator.java,复制以下代码:

import java.util.ArrayList; import java.util.List; public class FgcGenerator { // 使用静态列表持有对象引用,防止它们被回收 private static final List<byte[]> memoryHog = new ArrayList<>(); public static void main(String[] args) throws InterruptedException { System.out.println(">>> 开始制造频繁 FGC 场景 (纯原生 Java)..."); System.out.println(">>> 策略:不断分配 2MB 大对象填入老年代"); int count = 0; try { while (true) { // 创建一个 2MB 的字节数组 // 如果 Survivor 区小于 2MB,该对象会直接进入老年代 byte[] bigObject = new byte[2 * 1024 * 1024]; // 填入列表,阻止 GC 回收 memoryHog.add(bigObject); count++; // 每分配 50 个对象 (约 100MB) 打印一次状态并提示 GC if (count % 50 == 0) { long usedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024); System.out.println("已分配对象数: " + count + ", 当前堆使用: " + usedMemory + " MB"); System.out.println(">>> 手动触发 System.gc() 观察 FGC 频率..."); // 提示 JVM 进行 GC,此时由于老年代已满,极大概率触发 Full GC System.gc(); // 稍微休眠,让 GC 日志有时间输出,也避免 CPU 瞬间跑满 Thread.sleep(200); } } } catch (OutOfMemoryError e) { System.out.println("\n!!! 捕获到 OutOfMemoryError: " + e.getMessage()); System.out.println("!!! 如果配置了 -XX:+HeapDumpOnOutOfMemoryError,堆转储文件已生成。"); e.printStackTrace(); } } }

3. 在 Windows 上编译

打开 CMD 或 PowerShell,进入文件所在目录,执行:

javac FgcGenerator.java

4. 在 Windows 上运行 (关键步骤)

我们需要限制堆内存大小,以便快速复现 FGC 和 OOM。
准备工作:
确保存放 dump 文件的文件夹存在(例如 C:\temp)。

if not exist "C:\temp" mkdir "C:\temp"

执行命令:
复制以下命令到命令行运行(已配置好自动 dump 参数):

java -Xms128m -Xmx128m ^ -XX:NewSize=32m -XX:MaxNewSize=32m ^ -XX:+HeapDumpOnOutOfMemoryError ^ -XX:HeapDumpPath=C:\temp\fgc_native_dump.hprof ^ -XX:+PrintGCDetails ^ -Xloggc:C:\temp\fgc_native_gc.log ^ FgcGenerator

参数详解:
-Xms128m -Xmx128m: 将最大堆限制为 128MB,这样只需分配几十个 2MB 的对象就会填满,快速触发 FGC。
-XX:NewSize=32m -XX:MaxNewSize=32m: 限制年轻代大小。因为我们的对象是 2MB,如果年轻代太小,大对象会直接进入老年代,加速 FGC 的发生。
-XX:+HeapDumpOnOutOfMemoryError: 核心,OOM 时自动生成 hprof。
-XX:HeapDumpPath=…: 指定 hprof 文件保存位置。
-Xloggc:…: 同时生成 GC 日志,您可以打开这个 txt 文件看到密密麻麻的 Full GC 记录。

5. 观察现象

  1. 控制台输出:您会看到程序不断打印“已分配对象数…”,并且频繁出现 System.gc() 的提示。

  2. GC 日志:程序运行几秒到几十秒后(取决于机器速度),控制台或 C:\temp\fgc_native_gc.log 文件中会出现大量的 Full GC 记录,且回收效果很差(因为对象都被 memoryHog 列表引用着,无法回收)。

  3. 最终结果:

    • 程序抛出 java.lang.OutOfMemoryError: Java heap space。
    • 程序退出。
    • 检查 C:\temp 目录,您会发现生成了 fgc_native_dump.hprof 文件。

6. 如何验证是“频繁 FGC”导致的?

虽然 .hprof 本身不包含历史,但您可以结合生成的 GC 日志 (fgc_native_gc.log) 来证明:

  • 用记事本打开 C:\temp\fgc_native_gc.log。
  • 搜索 Full GC。
  • 您会看到在短时间内(例如 1 秒内)发生了多次 Full GC,且每次回收后的内存占用依然很高。这就是典型的“频繁 FGC”现场。
  • 然后用 MAT 打开 .hprof 文件,会发现 byte[] 数组占据了绝大部分内存,且被 java.util.ArrayList 引用,这就是导致 FGC 无法回收内存的元凶。

常见问题排查 (Windows)

  • 报错 “Error: Could not create the Java Virtual Machine”:可能是 -Xms 和 -Xmx 设置得比机器可用物理内存还小(极少见),或者参数格式有误。请确保直接复制上面的命令块。
  • 找不到 hprof 文件:检查 C:\temp 文件夹是否有写入权限,或者尝试将路径改为当前目录:-XX:HeapDumpPath=./fgc_dump.hprof。
  • 程序运行太久不崩溃:如果您的机器内存很大,默认的堆可能不止 128M。请确保 -Xmx128m 参数生效(可以在程序启动的第一行打印 Runtime.getRuntime().maxMemory() 确认)。
    这个方法完全不需要下载任何额外的 jar 包,是最纯净的复现方式。

JAVA包下载:点击下载JDK 25.
MAT分析工具下载:点击下载MAT分析工具.

7. 解压配置java运行环境启动mat分析程序

Win+R输入SystemPropertiesAdvanced打开环境变量页面配置好点确定关闭页面即可
变量名:JAVA_HOME
变量值:解压jdk后的目录路径

配置Path:%JAVA_HOME%\bin

验证Java运行环境无异常
启动MAT内存分析工具

http://www.jsqmd.com/news/461349/

相关文章:

  • Langflow 1.8 新特性:Knowledge Base 本地知识库组件完全上手指南
  • GNSS模块实战教程:大夏龙雀 DX-GP21,从硬件接线到 NMEA 数据解析(附完整代码)
  • 基于SpringBoot的校园设备维护报修系统设计与开发(源码+精品论文+答辩PPT等资料)
  • 基于微信小程序的剧本杀服务平台设计与实现
  • 正念笔记混乱想法3月9日
  • Odoo一键报税与金税合规方案
  • stm32f103c8t6呼吸灯
  • NASA- Prognostics Data Repository(预测数据存储库)
  • 为什么AI改AI越改越像AI?3个原因和正确的降AI方法
  • 2026南宁SEO优化服务新趋势:掌握这5大核心策略,轻松提升排名!
  • 数据结构--栈代码实现
  • Java面向对象—JDBC
  • 基于springboot的小米电商平台系统设计与实现设计与开发(源码+精品论文+答辩PPT等资料)
  • DeepSeek大模型驱动的空间智能引擎——镜像视界构建“人工智能+空间计算”新一代智能感知体系技术白皮书
  • 测试文章标题
  • 论成功与合作
  • 自研 Ollama 企业级网关:本地大模型生产化落地的工程化实践
  • 基于大数据爬虫+Hadoop+空气质量指数数据分析可视化设计与开发(源码+精品论文+答辩PPT等资料)
  • 1987年7月11日下午15-17点出生性格、运势和命运
  • AI证书纯线上考?过来人告诉你,这些“线上”环节的坑千万别踩!
  • Ubuntu 20.04 下 OpenClaw(龙虾)本地化部署保姆级教程
  • 深度解读C# 11 的 Required 成员:编译期状态验证强化
  • 认错贴 爱因斯坦经典5人逻辑题
  • 百度网盘下载太慢怎么办,如何提高网盘下载速度?
  • 2026年降AIGC率工具横评:便宜的和贵的差距到底有多大
  • 2026年DeepSeek写论文AI率太高?这5款降AI工具亲测有效
  • V-Ray 光照贴图烘焙参数适配教程
  • 基于BiGRU双向门控循环单元的锂电池SOH估计 [电池特征提取+SOH估计]Matlab代码(多输入单输出)
  • 虚拟机安装ngxin
  • Linux:读写锁与自旋锁