转储文件大杂烩详解(jstack,jmap,jvm)

kayokoi 发布于 2025-09-04 48 次阅读


“堆转储文件”(Heap Dump,通常由 -XX:+HeapDumpOnOutOfMemoryError 参数在发生OOM时自动生成,或由 jmap 命令手动生成)和 jstack 生成的“线程Dump”(Thread Dump)是两种不同类型但又互相关联的诊断信息

  1. 堆转储文件 (Heap Dump / .hprof 文件)

    • 是什么: 它是Java进程在某一特定时刻整个Java堆(Heap)内存的完整快照。想象一下给你的Java应用的“内存仓库”拍了一张包含所有货物(对象)、货物数量、货物大小以及货物之间如何堆放(引用关系)的详细照片。
    • 包含什么信息:
      • 堆中所有存活的对象实例。
      • 每个对象的类型(类名)。
      • 每个对象的大小。
      • 对象之间的引用关系(哪个对象持有了对另一个对象的引用)。
      • 可以追溯到GC Roots(垃圾回收的根对象,用于判断对象为何没有被回收)。
    • 主要用途:
      • 分析OutOfMemoryError (OOM) 的根本原因: 当发生 java.lang.OutOfMemoryError: Java heap space 时,堆转储文件是首要的分析对象。通过它,你可以看到OOM发生的瞬间,是哪些类型的对象、哪些具体的大对象占满了堆内存。
      • 定位内存泄漏 (Memory Leak): 通过对比不同时间点的堆转储,或者分析单个堆转储中不应继续存活但依然被引用的对象,可以找到内存泄漏的源头。
      • 了解应用的内存使用模式: 分析哪些对象占用了大部分内存,是否有不合理的内存使用等。
    • 生成方式:
      • JVM参数自动生成:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump/
      • 手动命令:jmap -dump:format=b,file=heap.hprof <PID>
      • 其他工具:VisualVM, JMC, Arthas (heapdump命令) 等。
    • 分析工具: Eclipse MAT (Memory Analyzer Tool), JVisualVM, YourKit, JProfiler 等。
  2. 线程Dump (Thread Dump / jstack 的输出)

    • 是什么: 它是Java进程在某一特定时刻所有线程(或指定线程)的活动状态和执行堆栈的快照。想象一下给工厂里所有“工人”(线程)在同一时间点拍一张集体工作照,照片上显示了每个工人在干什么活,进行到哪一步了。
    • 包含什么信息:
      • 每个线程的名称、ID(Java内部ID和操作系统本地线程ID nid)、优先级。
      • 每个线程的当前状态(RUNNABLE, BLOCKED, WAITING, TIMED_WAITING 等)。
      • 每个线程的调用堆栈 (Stack Trace):即从当前正在执行的方法,一层层向上追溯到方法的调用者,直到线程的入口点。
      • 锁信息(使用 -l 参数时更详细):线程当前持有哪些锁,正在等待哪些锁。
    • 主要用途:
      • 诊断线程死锁 (Deadlock): jstack 能自动检测并报告Java层面的死锁。
      • 定位CPU飙高原因: 结合 top -Hp <PID> 找到高CPU线程后,用 jstack 查看其堆栈,多次采样对比,找到“热点代码”。
      • 分析应用卡顿、无响应: 查看是否有大量线程处于 BLOCKED 状态(锁竞争),或 WAITING/TIMED_WAITING 状态(等待外部资源、IO、或条件变量)。
      • 理解应用的并发行为。
    • 生成方式:
      • jstack <PID>jstack -l <PID>
      • kill -3 <PID> (SIGQUIT信号,JVM会将线程dump输出到标准输出/错误流)
      • 其他工具:VisualVM, JMC, Arthas (thread命令) 等。
    • 分析工具: 可以直接阅读文本输出,也可以使用一些在线或本地的线程Dump分析工具(如fastThread.io,VisualVM内置的分析器等)。
  3. hs_err_pid<PID>.log 文件 (JVM崩溃日志 / Fatal Error Log)

    • 是什么: 当JVM遇到致命错误(通常是JVM自身Bug、本地代码(JNI)崩溃、或者非常严重的资源耗尽导致JVM无法继续稳定运行时)而异常终止 (crash) 时,会尝试生成这个日志文件。这是JVM的“真正遗言”。
    • 包含什么信息:
      • 导致崩溃的事件摘要。
      • 崩溃时所有线程的(部分或完整)堆栈信息(类似于一次 jstack 的输出)。
      • 寄存器信息、内存映射信息、加载的动态链接库列表。
      • 有时会包含一些堆内存的摘要信息,但它不是一个完整的堆转储文件
    • 主要用途: 主要用于分析JVM崩溃的深层原因,通常需要更专业的JVM知识或提交给JVM厂商/社区分析。
    • 与前两者的关系: 它可能包含线程堆栈信息(类似jstack),也可能提及内存相关问题,但它本身不是专门用于内存泄漏分析的Heap Dump,也不是专门用于线程行为分析的Thread Dump,而是JVM崩溃时的综合报告。

它们之间的关系和区别总结:

特性 堆转储文件 (Heap Dump) 线程Dump (jstack 输出) hs_err_pid<PID>.log (JVM崩溃日志)
关注点 内存中的对象数据 线程的执行状态和路径 JVM崩溃时的整体状态
核心内容 对象实例、类信息、引用关系、大小 线程状态、调用栈、锁信息 崩溃原因、线程栈、部分内存、寄存器等
主要解决 OOM、内存泄漏、内存结构分析 死锁、CPU飙高、应用卡顿、线程行为分析 JVM自身崩溃、JNI错误等致命问题
生成时机 OOM时自动、jmap手动、其他工具手动 jstack手动、kill -3、其他工具手动 JVM发生致命错误时自动生成

简单来说:

  • 当你遇到 OutOfMemoryError,首先要找的是堆转储文件 (Heap Dump),用它来分析是哪些对象把内存撑爆了。
  • 当你遇到 CPU飙高、应用卡死、线程死锁,首先要用 jstack 生成线程Dump,用它来分析是哪个线程的哪段代码出了问题。
  • 当你发现Java进程意外崩溃消失了,并且留下了一个 hs_err_pid<PID>.log 文件,那这个文件就是分析JVM为何崩溃的关键。这个文件里可能包含了线程信息,能辅助判断崩溃前的状态,但如果问题是内存泄漏导致的OOM后引发的不稳定,最终还是需要OOM时生成的Heap Dump来分析内存。

这三者都是Java问题排查中非常重要的“遗言”,但它们揭示的是不同层面的问题。在OOM的场景下,-XX:+HeapDumpOnOutOfMemoryError 生成的堆转储文件是分析内存问题的核心;而如果OOM导致了应用卡顿或你想了解OOM发生时其他线程在做什么,那么配合一个线程dump(可能在 hs_err_pid.log 中有,或者在OOM没导致JVM立即崩溃前手动抓取)会更有帮助。