堆内存 dump 如何生成

在排查 Java 应用运行缓慢、内存占用高这类问题时,内存 dump 是个实用的工具。它能记录某一时刻 JVM 堆中所有对象的状态,帮助我们分析内存使用情况,找出潜在的内存泄漏或大对象占用。

什么时候需要生成堆 dump

比如你部署了一个后台服务,发现服务器内存一路飙升,重启后又慢慢上来,这时候光看日志可能看不出什么。通过生成堆 dump 文件,就能用工具(如 Eclipse MAT、VisualVM)打开分析,看看是哪些对象一直在堆积。

使用 jmap 命令生成 dump

最常用的方法是 JDK 自带的 jmap 工具。假设你的 Java 进程 PID 是 12345,可以在终端执行:

jmap -dump:format=b,file=heap.hprof 12345

这条命令会把当前堆内存快照写入当前目录下的 heap.hprof 文件。文件大小通常和堆使用量成正比,几百 MB 到几个 GB 都有可能,注意磁盘空间。

通过 JMX 远程触发

如果应用跑在内网服务器上,不能直接登录操作,可以通过 JMX 方式远程连接。先确保启动 Java 程序时开启了 JMX 支持:

java -Dcom.sun.management.jmxremote.port=9999 \
     -Dcom.sun.management.jmxremote.authenticate=false \
     -Dcom.sun.management.jmxremote.ssl=false \
     -jar your-app.jar

然后在本地用 VisualVM 或 JConsole 连接上去,找到“堆 Dump”按钮一点就行。这种方式适合调试线上环境的问题,尤其是配合内网穿透工具暴露 JMX 端口的时候。

代码中主动触发 dump

有时候你想在特定条件下自动生成 dump,比如某个接口调用后怀疑有内存泄漏,可以在代码里加个临时逻辑:

import java.lang.management.ManagementFactory;
import com.sun.management.HotSpotDiagnosticMXBean;

public class HeapDumper {
    private static final String HOTSPOT_BEAN_NAME =
        "com.sun.management:type=HotSpotDiagnostic";

    public static void dumpHeap(String filePath) {
        try {
            HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(
                ManagementFactory.getPlatformMBeanServer(),
                HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class);
            mxBean.dumpHeap(filePath, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

调用 HeapDumper.dumpHeap("/tmp/heap.hprof") 就能生成文件。上线前记得删掉这类代码,避免被误用。

小技巧:设置 OOM 时自动导出

如果问题是出现在内存溢出(OutOfMemoryError)时,可以提前加参数让 JVM 自动保存 dump:

java -XX:+HeapDumpOnOutOfMemoryError \
     -XX:HeapDumpPath=/data/dumps \
     -jar app.jar

这样一旦发生 OOM,JVM 会自动把堆信息写进去指定目录,省得错过时机。

生成 dump 只是第一步,后续还得用分析工具打开看具体对象分布。不过对于定位内存问题来说,这一步已经迈出了最关键的那一下。