一、Heap Dump概述
常见扩展名:.hprof
生成方式
- 使用
jmap工具:jmap -dump:format=b,file=heap.hprof <pid> - JVM 启动参数自动生成(如 OOM 时):
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heap.hprof
解析工具
1. Eclipse Memory Analyzer (MAT)
- 官网:https://www.eclipse.org/mat/
- 用法:
- 安装并打开 MAT。
- File > Open Heap Dump,选择
.hprof文件。 - 自动分析内存泄漏嫌疑对象、对象引用链等。
2. VisualVM
- 官网:https://visualvm.github.io/
- 用法:
- 启动 VisualVM。
- File > Load,选择
.hprof文件。 - 查看类实例、对象大小分布、GC Roots 路径等。
3. 命令行工具
jhat:
启动后可通过浏览器访问 http://localhost:7000 进行分析(但较老旧,不推荐)。jhat heap.hprof
总结
- Heap Dump:用于分析内存对象分布和泄漏,推荐用 MAT、VisualVM。
- Thread Dump:用于分析线程状态和死锁,推荐用 FastThread、jstack。
- 解析 dump 文件时,关注对象引用链、GC Roots、线程锁关系等关键信息。
http://tool111.com
二、Heap Dump 详解
1. Heap Dump 文件结构
Heap Dump(如 .hprof 文件)本质上是 JVM 内存堆的快照,记录了:
- 所有对象实例(包括类名、字段、引用关系、大小等)
- 类定义信息
- GC Roots
- 线程信息(有时包含)
hprof 文件内容主要包括:
- Header:文件头,标识为 hprof 格式
- Records:一系列记录(如 LOAD CLASS、HEAP DUMP SEGMENT、STRING等)
2. 解析过程原理
解析 heap dump 的工具(如 MAT、VisualVM)大致遵循以下步骤:
步骤一:读取并解析文件结构
- 解析 header,确定版本、字节序等
- 顺序读取各个记录,建立对象、类、字符串等的索引
步骤二:重建对象图
- 根据对象实例记录,重建堆中所有对象
- 解析对象字段,将对象间的引用关系(指针)还原为图结构
步骤三:分析引用链和 GC Roots
- 寻找 GC Roots(如静态变量、线程栈、JNI引用等)
- 从 GC Roots 出发遍历对象图,分析哪些对象可达
- 统计各个对象的大小、引用链,查找内存泄漏嫌疑对象(如大对象、长链条)
步骤四:生成报告
- 统计各类对象的数量和大小
- 展示对象之间的引用关系
- 标记泄漏嫌疑对象、分析内存分布
核心原理:
通过对象之间的引用关系,重建堆内存的对象图,并结合 GC Roots,分析对象生命周期和可达性。
三、HPROF文件结构
HPROF 文件结构总览
HPROF 文件主要由以下几部分组成:
- Header(文件头)
- Records(记录区)
- 包含一系列类型不同的记录(如字符串、类加载、对象实例、堆快照等)
Header(文件头)
HPROF 文件头内容如下:
- 格式标识:ASCII 字符串
"JAVA PROFILE 1.0.1" - 换行符:
\n - ID Size(4字节):指示后续所有 ID 字段(如对象ID、类ID等)的字节长度(通常为4或8字节)
- 高精度时间戳(8字节):long 型,单位为毫秒
示例(16字节头部):
JAVA PROFILE 1.0.1\n
[idSize: 4字节]
[timestamp: 8字节]
Records(记录区)
HPROF 文件主体由一系列记录构成,每条记录结构如下:
| 字段 | 长度 | 说明 |
|---|---|---|
| Tag | 1字节 | 记录类型 |
| Time | 4字节 | 记录生成时间(相对文件头时间) |
| Length | 4字节 | 记录内容长度 |
| Body | Length字节 | 记录内容 |
主要 Tag 类型
| Tag (16进制) | 含义 |
|---|---|
| 0x01 | STRING |
| 0x02 | LOAD CLASS |
| 0x0A | STACK FRAME |
| 0x0B | STACK TRACE |
| 0x0C | ALLOC SITES |
| 0x0F | HEAP DUMP |
| 0x1C | HEAP DUMP SEGMENT |
| 0x1D | HEAP DUMP END |
常见记录类型说明
1. STRING (Tag: 0x01)
记录字符串常量(如类名、字段名等)。
| 字段 | 长度 | 说明 |
|---|---|---|
| String ID | idSize | 字符串的唯一ID |
| UTF-8 字符 | 变长 | 字符串内容 |
2. LOAD CLASS (Tag: 0x02)
记录类的加载信息。
| 字段 | 长度 | 说明 |
|---|---|---|
| Class Serial | 4字节 | 类的序号 |
| Class Object | idSize | 类对象ID |
| Stack Trace | 4字节 | 堆栈跟踪ID |
| Class Name | idSize | 类名字符串ID |
3. HEAP DUMP / HEAP DUMP SEGMENT (Tag: 0x0F/0x1C)
堆快照的主要内容,包含对象、类、数组等实例。
HEAP DUMP SEGMENT 结构:
由一系列子记录组成,每个子记录结构如下:
| 子Tag | 说明 |
|---|---|
| 0xFF | ROOT UNKNOWN |
| 0x01 | ROOT JNI GLOBAL |
| 0x21 | CLASS DUMP |
| 0x22 | INSTANCE DUMP |
| 0x23 | OBJECT ARRAY DUMP |
| 0x24 | PRIMITIVE ARRAY DUMP |
| … | 其他类型 |
重要子记录结构举例:
CLASS DUMP (0x21)
记录类定义,包括字段、方法等。
| 字段 | 长度 | 说明 |
|---|---|---|
| Class ObjectID | idSize | 类对象ID |
| Stack TraceID | 4字节 | 堆栈跟踪ID |
| Super ClassID | idSize | 父类对象ID |
| Class LoaderID | idSize | 类加载器对象ID |
| Name StringID | idSize | 类名字符串ID |
| Instance Size | 4字节 | 实例大小 |
| … | … | 字段列表等 |
INSTANCE DUMP (0x22)
记录对象实例,包括字段值。
| 字段 | 长度 | 说明 |
|---|---|---|
| ObjectID | idSize | 对象ID |
| Stack TraceID | 4字节 | 堆栈跟踪ID |
| Class ObjectID | idSize | 类对象ID |
| Data Length | 4字节 | 字段数据长度 |
| Field Data | 变长 | 字段值内容 |
OBJECT ARRAY DUMP (0x23)
对象数组实例。
| 字段 | 长度 | 说明 |
|---|---|---|
| ArrayID | idSize | 数组对象ID |
| Stack TraceID | 4字节 | 堆栈跟踪ID |
| NumElements | 4字节 | 元素数量 |
| ArrayClassID | idSize | 数组类型ID |
| ElementIDs | idSize*N | 每个元素对象ID |
PRIMITIVE ARRAY DUMP (0x24)
基本类型数组实例。
| 字段 | 长度 | 说明 |
|---|---|---|
| ArrayID | idSize | 数组对象ID |
| Stack TraceID | 4字节 | 堆栈跟踪ID |
| NumElements | 4字节 | 元素数量 |
| ElementType | 1字节 | 元素类型(如int、byte等) |
| Values | 变长 | 元素值 |
ID Size 与对象引用
- HPROF 文件中的所有对象、类、字符串等都用 ID 表示,长度由文件头的 idSize 指定(通常为 4 或 8 字节)。
- 这些 ID 用于在各个记录之间建立引用关系。
扩展说明
- HPROF 格式在不同 JVM 版本间可能略有差异,建议使用主流工具(MAT、VisualVM)解析。
- HPROF 也可以用于 CPU/线程分析,但现代 JVM 更推荐使用更高效的格式(如 JFR)。
总结
HPROF 文件由头部和记录区组成,记录区通过不同的 Tag 标识不同类型的数据,如字符串、类定义、对象实例、数组等。解析 HPROF 文件时,需根据 Tag 和 idSize,逐条解析和关联各个对象与类的信息,最终重建 JVM 堆内存的快照结构。
创作不易,点赞关注,持续更新~~~
1538

被折叠的 条评论
为什么被折叠?



