MCP-MAT 堆转储文件分析实战教程
基于真实生产环境 5.4GB Heap Dump 分析经验总结
目录
- 简介
- 环境准备与安装
- [MCP 配置详解](#mcp 配置详解)
- 核心命令使用指南
- 实战案例分析
- 高级分析技巧
- 常见问题排查
简介
什么是 MCP-MAT?
MCP-MAT 是 Eclipse Memory Analyzer (MAT) 的 Model Context Protocol 服务,让 AI 助手能够直接分析 Java 堆转储文件。
本教程特点
- ✅ 基于 5.4GB 真实生产 Heap Dump 分析经验
- ✅ 涵盖 6 大核心命令 的详细用法
- ✅ 提供 10+ 个实战案例 和 Prompt 模板
- ✅ 包含 权限配置 和 环境调优 完整指南
环境准备与安装
步骤 1: 系统要求检查
1
2
3
4
5
6
7
8
9
| # 检查 Java 版本(需要 JDK 11+)
java -version
# 检查 npx 是否可用(用于安装 MCP 服务)
npx --version
# 检查磁盘空间(至少需要堆转储文件 3 倍空间)
df -h # Linux/macOS
dir # Windows
|
步骤 2: 下载 Eclipse MAT
Windows 下载
1
2
3
4
5
6
7
8
9
| # 方法 1: 官网下载
# 访问:https://www.eclipse.org/mat/downloads.php
# 选择 "Memory Analyzer 1.16.1" → Windows 64-bit
# 方法 2: 直接下载链接
wget https://www.eclipse.org/downloads/download.php?file=/mat/1.16.1/MemoryAnalyzer-1.16.1.20250109-win32.win32.x86_64.zip -O mat.zip
# 解压
Expand-Archive mat.zip -DestinationPath "C:\Program Files"
|
Linux 下载
1
2
3
4
| # 下载并解压
wget https://download.eclipse.org/mat/1.16.1/mta-java-1.16.1-linux-gtk.x86_64.tar.gz
tar -xzf mta-java-1.16.1-linux-gtk.x86_64.tar.gz -C /opt/
ln -s /opt/mta-java-1.16.1 /opt/mat
|
步骤 3: 安装 MCP-MAT 服务
1
2
3
4
5
6
7
8
| # 全局安装(推荐)
npm install -g mcp-mat
# 或使用 npx 临时运行
npx -y mcp-mat
# 验证安装
npx -y mcp-mat --version
|
步骤 4: 验证 MAT 环境
使用 mat_healthcheck 命令验证:
1
2
3
| /mat_healthcheck
mat_home="C:\Program Files\mat"
java_path="C:\Program Files\Java\jdk-17\bin\java.exe"
|
预期输出:
1
2
3
4
5
6
| {
"status": "ok",
"mat_version": "1.16.1",
"java_version": "17.0.x",
"mat_home": "C:\\Program Files\\mat"
}
|
MCP 配置详解
配置方式 1: Claude Code settings.json
文件位置: ~/.claude/settings.local.json 或项目 .claude/settings.local.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| {
"mcpServers": {
"mat": {
"command": "npx",
"args": ["-y", "mcp-mat"],
"env": {
"MAT_HOME": "C:\\Program Files\\mat",
"JAVA_PATH": "C:\\Program Files\\Java\\jdk-17\\bin\\java.exe"
}
}
},
"permissions": {
"allow": [
"mcp__mat__mat_healthcheck",
"mcp__mat__mat_index_status",
"mcp__mat__mat_run_command",
"mcp__mat__mat_oql_query",
"mcp__mat__mat_parse_report"
]
}
}
|
配置方式 2: Cline (VS Code)
打开: VS Code → 设置 → MCP Servers → 添加服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| {
"mcpServers": {
"mat": {
"command": "node",
"args": [
"C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\mcp-mat\\dist\\index.js"
],
"env": {
"MAT_HOME": "C:\\Program Files\\mat",
"JAVA_PATH": "C:\\Program Files\\Java\\jdk-17\\bin\\java.exe"
}
}
}
}
|
配置方式 3: Continue IDE 插件
文件位置: ~/.continue/config.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| {
"tabAutocompleteModel": "claude-sonnet-4-5",
"models": [
{
"title": "Claude Code",
"provider": "anthropic",
"model": "claude-sonnet-4-5"
}
],
"mcpServers": [
{
"name": "mat",
"command": "npx",
"args": ["-y", "mcp-mat"],
"env": {
"MAT_HOME": "C:\\Program Files\\mat"
}
}
]
}
|
权限配置说明
根据你的分析需求,配置不同的权限级别:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| {
"permissions": {
"allow": [
// 基础检查权限
"mcp__mat__mat_healthcheck",
"mcp__mat__mat_index_status",
// 核心分析权限
"mcp__mat__mat_run_command",
"mcp__mat__mat_oql_query",
"mcp__mat__mat_parse_report",
// Bash 命令(用于解压结果文件)
"Bash(unzip:*)",
"Bash(ls *.html)",
"Bash(dir *.txt)"
]
}
}
|
核心命令使用指南
命令 1: mat_healthcheck - 环境检查
用途: 验证 MAT 和 Java 环境是否正常
1
2
3
| /mat_healthcheck
mat_home="D:\BaiduNetdiskDownload\MemoryAnalyzer-1.16.1"
java_path="C:\Program Files\Java\jdk-17\bin\java.exe"
|
输出示例:
1
2
3
4
5
6
| {
"status": "ok",
"exit_code": 0,
"stdout_tail": "MAT 1.16.1 ready",
"stderr_tail": ""
}
|
常见错误:
| 错误 | 原因 | 解决 |
|---|
Java runtime not found | JAVA_PATH 配置错误 | 检查 java.exe 路径 |
MAT not found | MAT_HOME 配置错误 | 检查 mat 目录是否存在 |
Permission denied | 权限不足 | 添加 mcp__mat__mat_healthcheck 权限 |
命令 2: mat_index_status - 索引状态检查
用途: 检查堆转储文件是否已建立索引(首次分析会自动创建索引)
1
2
| /mat_index_status
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
|
输出示例:
1
2
3
4
5
6
| {
"status": "ok",
"exit_code": 0,
"index_path": "D:\\BaiduNetdiskDownload\\heapDump\\heap_dump_172.29.10.122_1774096961008.index",
"index_size": "18.6 MB"
}
|
状态说明:
| 状态 | 说明 | 操作 |
|---|
indexed | 已建立索引 | 可直接分析 |
building | 索引构建中 | 等待完成 |
not_found | 无索引 | 首次查询会自动创建 |
命令 3: mat_run_command - 执行 MAT 内置命令
用途: 执行 56 个内置 MAT 分析命令
语法格式
1
2
3
4
5
6
7
8
| /mat_run_command
heap_path="<堆转储文件路径>"
command_name="<命令名称>"
command_args="<可选参数>"
format="<txt|csv|html>"
limit="<结果数量>"
timeout_sec="<超时秒数>"
xmx_mb="<MAT 堆内存 MB>"
|
常用命令示例
1. histogram - 类直方图分析
1
2
3
4
5
6
| # 查看内存占用最高的类
/mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="histogram"
format="txt"
limit="30"
|
输出示例:
1
2
3
4
5
6
7
| Class Name | Objects | Shallow Heap
--------------------------------------------------
byte[] | 338,898 | 2,463,164,632
char[] | 5,072,080| 1,151,162,856
java.lang.String | 5,344,092| 128,258,208
java.lang.Object[] | 1,607,211| 118,687,504
java.util.HashMap$Node | 2,382,397| 76,236,704
|
2. 查询特定类的直方图
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="histogram"
command_args="java.nio.DirectByteBuffer"
format="txt"
|
3. gc_roots - 分析 GC Roots
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="gc_roots"
command_args="java.util.concurrent.LinkedBlockingQueue"
format="txt"
limit="20"
|
输出示例:
1
2
3
4
5
6
7
8
| GC Roots Analysis for java.util.concurrent.LinkedBlockingQueue
Root Type | Count | Percentage
-------------------|-------|------------
System Class | 4,828 | 71.8%
Thread | 1,661 | 24.7%
Busy Monitor | 161 | 2.4%
JNI Global | 72 | 1.1%
|
4. path2gc - 追踪对象到 GC Root 的路径
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="path2gc"
command_args="0x63d835b28"
format="txt"
limit="30"
|
输出示例:
1
2
3
4
5
6
| Class Name | Shallow Heap | Retained Heap
------------------------------------------------------------------------------------------------
java.lang.Object[262208] | 2,097,664 | 853,344,368
|- [0] → com.lmax.disruptor.RingBuffer @ 0x63d835b28 | 64 | 853,344,368
|- dataProvider → BatchEventProcessor @ 0x63d6b9d48 | 48 | 12,456
|- <Java Local> → Log4j2-TF-4-AsyncLoggerConfig-3 | 120 | 17,160
|
5. thread_overview - 线程概览
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="thread_overview"
format="txt"
limit="50"
|
6. thread_details - 线程详情
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="thread_details"
command_args="Log4j2-TF-4-AsyncLoggerConfig-3"
format="txt"
|
7. dominator_tree - 支配树分析
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="dominator_tree"
format="txt"
limit="50"
|
8. find_strings - 查找字符串
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="find_strings"
command_args="password"
format="txt"
limit="100"
|
9. collection_fill_ratio - 集合填充率
1
2
3
4
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="collection_fill_ratio"
format="txt"
|
10. system_properties - 系统属性
1
2
3
4
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="system_properties"
format="txt"
|
命令 4: mat_oql_query - OQL 对象查询
用途: 执行 SQL 风格的对象查询
基本语法
1
2
3
4
5
6
| /mat_oql_query
heap_path="<堆转储路径>"
oql="<OQL 查询语句>"
format="<txt|csv|html>"
limit="<结果数量>"
timeout_sec="<超时秒数>"
|
查询示例
1. 查询所有 String 对象
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT * FROM java.lang.String"
format="txt"
limit="100"
|
2. 查询特定条件的对象
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT s FROM java.lang.String s WHERE toString(s.value) LIKE '%error%'"
format="txt"
limit="50"
|
3. 查询字段值
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT b.capacity FROM java.nio.DirectByteBuffer b"
format="txt"
limit="1000"
|
4. 统计对象数量
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT COUNT(*) FROM java.util.concurrent.LinkedBlockingQueue"
format="txt"
|
5. 查询线程对象
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT t.name, t.threadLocals FROM java.lang.Thread t WHERE t.name LIKE '%Log4j2%'"
format="txt"
limit="20"
|
6. 查询 RingBuffer 对象
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT r, r.bufferSize FROM com.lmax.disruptor.RingBuffer r"
format="txt"
|
7. 查询 SAP HANA 连接对象
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT * FROM com.sap.dbtech.jdbc.BasicChannelSession"
format="txt"
limit="50"
|
OQL 语法限制
⚠️ 重要: MAT OQL 不支持以下 SQL 语法:
| 不支持的语法 | 替代方案 |
|---|
IS NOT NULL | 查询后在结果中过滤 |
GROUP BY | 手动聚合或使用 mat_run_command |
ORDER BY | 查询后排序 |
JOIN | 分别查询后关联 |
DISTINCT | 查询后去重 |
命令 5: mat_parse_report - 生成预定义报告
用途: 运行 MAT 预定义分析报告
1
2
3
4
5
6
| /mat_parse_report
heap_path="<堆转储路径>"
report_id="<报告 ID>"
options="<可选参数>"
timeout_sec="<超时秒数>"
xmx_mb="<MAT 堆内存 MB>"
|
预定义报告 ID
| 报告 ID | 说明 |
|---|
leak_report | 内存泄漏分析报告 |
leak_suspects | 泄漏嫌疑对象报告 |
thread_overview | 线程概览报告 |
component_report | 组件分析报告 |
示例
1
2
3
4
5
| /mat_parse_report
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
report_id="leak_suspects"
timeout_sec="180"
xmx_mb="4096"
|
命令 6: mat_oql_spec - 获取 OQL 语法规范
输出: OQL 语法规范和支持的功能列表
实战案例分析
案例 1: Log4j2 RingBuffer 内存泄漏分析
场景: 应用日志堆积,内存占用持续增长。
分析步骤
步骤 1: 查看内存占用 Top 类
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="histogram"
format="txt"
limit="30"
|
步骤 2: 查找 RingBuffer 对象
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT * FROM com.lmax.disruptor.RingBuffer"
format="txt"
|
步骤 3: 分析 RingBuffer 的 GC Roots
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="gc_roots"
command_args="com.lmax.disruptor.RingBuffer"
format="txt"
limit="20"
|
步骤 4: 追踪引用链
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="path2gc"
command_args="0x63d835b28"
format="txt"
limit="30"
|
步骤 5: 查看消费者线程状态
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="thread_details"
command_args="Log4j2-TF-4-AsyncLoggerConfig-3"
format="txt"
|
分析结论
| 发现 | 数值 |
|---|
| RingBuffer 占用 | 853 MB |
| 积压日志事件 | 262,143 个 |
| 消费者线程状态 | BLOCKED |
| 阻塞位置 | OutputStreamManager.writeBytes() |
修复建议
1
2
3
4
5
6
7
| <!-- log4j2.xml -->
<AsyncLogger name="com.example" level="info" includeLocation="false">
<AsyncLoggerConfig>
<Property name="WaitStrategy">Timeout</Property>
<Property name="TimeoutNanoSeconds">1000000</Property>
</AsyncLoggerConfig>
</AsyncLogger>
|
案例 2: 线程池任务队列堆积分析
场景: RocketMQ 消费者任务处理缓慢,队列积压。
分析步骤
步骤 1: 查找 LinkedBlockingQueue
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="histogram"
command_args="java.util.concurrent.LinkedBlockingQueue"
format="txt"
|
步骤 2: 统计队列数量
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT COUNT(*) FROM java.util.concurrent.LinkedBlockingQueue"
format="txt"
|
步骤 3: 查询大队列
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT q, q.elementCount FROM java.util.concurrent.LinkedBlockingQueue q WHERE q.elementCount > 1000"
format="txt"
limit="50"
|
步骤 4: 分析队列持有者
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="path2gc"
command_args="0x68c21a228"
format="txt"
limit="30"
|
步骤 5: 查看关联线程
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT t.name FROM java.lang.Thread t WHERE t.name LIKE '%ConsumeMessageThread%'"
format="txt"
limit="50"
|
分析结论
| 发现 | 数值 |
|---|
| LinkedBlockingQueue 实例数 | 176 个 |
| 总积压任务数 | 15,907 个 |
| 关联消费者线程 | 138 个 |
| 主要积压原因 | 日志 I/O 阻塞导致消费慢 |
案例 3: SAP HANA 连接泄漏分析
场景: 数据库连接数持续增长,怀疑连接泄漏。
分析步骤
步骤 1: 查找 SAP HANA 连接对象
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT * FROM com.sap.dbtech.jdbc.BasicChannelSession"
format="txt"
limit="50"
|
步骤 2: 统计连接数量
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT COUNT(c) FROM com.sap.dbtech.jdbc.BasicChannelSession c"
format="txt"
|
步骤 3: 分析连接持有者
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="path2gc"
command_args="0x63e558e80"
format="txt"
limit="30"
|
步骤 4: 查看 HikariCP 连接池状态
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT * FROM com.zaxxer.hikari.pool.HikariPool"
format="txt"
|
分析结论
| 发现 | 数值 |
|---|
| BasicChannelSession 实例 | 89 个 |
| 占用内存 | 805 MB |
| GC Root 类型 | Thread (线程持有) |
| 持有线程 | sap housekeeper + 业务线程 |
修复建议
1
2
3
4
5
6
7
| # application.yml
spring:
datasource:
hikari:
leak-detection-threshold: 60000 # 60 秒泄漏检测
max-lifetime: 1800000 # 30 分钟最大生命周期
idle-timeout: 600000 # 10 分钟空闲回收
|
案例 4: DirectByteBuffer 堆外内存分析
场景: 堆外内存占用过高,怀疑 DirectByteBuffer 泄漏。
分析步骤
步骤 1: 统计 DirectByteBuffer 数量
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="histogram"
command_args="java.nio.DirectByteBuffer"
format="txt"
|
步骤 2: 查询容量分布
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT b.capacity FROM java.nio.DirectByteBuffer b"
format="txt"
limit="3000"
|
步骤 3: 分析 PoolChunk 实际分配
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT c, c.chunkSize, c.freeBytes FROM io.netty.buffer.PoolChunk c"
format="txt"
|
步骤 4: 追踪持有者
1
2
3
4
5
6
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="path2gc"
command_args="0x5f150e668"
format="txt"
limit="30"
|
分析结论
| 发现 | 数值 |
|---|
| DirectByteBuffer 实例 | 2,338 个 |
| 堆上占用 | 149,632 字节 |
| PoolChunk 数量 | 16 个 |
| 实际堆外内存 | 256 MB (已用 3.5 MB) |
关键发现: 之前误将 capacity 字段相加得到 33.2 GB,实际是 Netty 内存池的视图引用,真实堆外内存仅 256 MB。
案例 5: BLOCKED 线程级联分析
场景: 系统响应慢,大量线程阻塞。
分析步骤
步骤 1: 生成线程概览报告
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="thread_overview"
format="txt"
limit="100"
|
步骤 2: 查找 BLOCKED 线程
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT t.name, t.blockedCount FROM java.lang.Thread t WHERE t.blockedCount > 0"
format="txt"
limit="100"
|
步骤 3: 分析阻塞根源
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="thread_details"
command_args="Log4j2-TF-4-AsyncLoggerConfig-3"
format="txt"
|
分析结论
| 发现 | 数值 |
|---|
| BLOCKED 线程总数 | 186 个 |
| 阻塞在日志写入 | ~100+ 个 |
| 阻塞在 RingBuffer | ~50+ 个 |
| 根源 | OutputStreamManager 同步方法 |
案例 6: unreachable 对象和 Finalizer 分析
场景: GC 频繁,怀疑 Finalizer 阻塞。
分析步骤
步骤 1: 统计不可达对象
1
2
3
4
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT COUNT(*) FROM java.lang.Object o WHERE !isReachable(o)"
format="txt"
|
步骤 2: 查看 Finalizer 队列
1
2
3
4
5
| /mat_run_command
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
command_name="histogram"
command_args="java.lang.ref.Finalizer"
format="txt"
|
步骤 3: 分析最终引用对象
1
2
3
4
5
| /mat_oql_query
heap_path="D:\BaiduNetdiskDownload\heapDump\heap_dump_172.29.10.122_1774096961008.hprof"
oql="SELECT * FROM java.lang.ref.Finalizer"
format="txt"
limit="100"
|
分析结论
| 发现 | 数值 |
|---|
| 不可达对象总数 | 3,394,909 个 |
| 不可达对象内存 | ~235 MB |
| Finalizer 队列深度 | 0 (空) |
| 结论 | GC 频率问题,非 Finalizer 阻塞 |
高级分析技巧
技巧 1: 组合命令深度分析
1
2
3
4
5
6
7
8
| # 先 histogram 找到大对象
/mat_run_command command_name="histogram" limit="20"
# 再 gc_roots 分析引用源
/mat_run_command command_name="gc_roots" command_args="java.util.HashMap"
# 最后 path2gc 追踪具体对象
/mat_run_command command_name="path2gc" command_args="0x12345678"
|
技巧 2: OQL 高级查询模式
1
2
3
4
5
6
7
8
9
10
11
| -- 模糊查询
SELECT * FROM java.lang.String s WHERE toString(s.value) LIKE '%error%'
-- 数组查询
SELECT a[0] FROM java.lang.Object[] a WHERE arrayLength(a) > 100
-- 继承查询 (查询所有 List 实现)
SELECT * FROM java.util.List
-- 字段过滤
SELECT m.myField FROM com.example.MyClass m
|
技巧 3: 批量分析多个 Dump 文件
1
2
3
4
5
6
7
| # 对比正常状态
/mat_run_command heap_path="heap_normal.hprof" command_name="histogram"
# 对比异常状态
/mat_run_command heap_path="heap_abnormal.hprof" command_name="histogram"
# 找出差异最大的类
|
技巧 4: 结果文件处理
1
2
3
4
5
6
7
8
| # 解压查询结果
unzip -o heap_dump_172.29.10.122_1774096961008_Query.zip -d query_result
# 查看生成的文件
ls -la query_result/pages/
# 提取文本结果
cat query_result/pages/Query_Command.txt
|
技巧 5: 性能调优参数
1
2
3
4
5
6
7
8
9
| # 增加 MAT 堆内存(分析大文件时)
/mat_run_command
heap_path="large_dump.hprof"
xmx_mb="8192"
timeout_sec="600"
# 使用 CSV 格式便于后续处理
/mat_oql_query
format="csv"
|
常见问题排查
Q1: MAT 启动失败
错误: Java runtime not found
解决:
1
2
3
4
5
6
| {
"env": {
"MAT_HOME": "C:\\Program Files\\mat",
"JAVA_PATH": "C:\\Program Files\\Java\\jdk-17\\bin\\java.exe"
}
}
|
Q2: 命令超时
错误: Timeout after 60 seconds
解决:
1
2
3
| /mat_run_command
timeout_sec="300"
xmx_mb="4096"
|
Q3: OQL 语法错误
错误: Encountered "GROUP" at line 1...
原因: MAT OQL 不支持 GROUP BY
解决: 使用简单查询,手动聚合结果
Q4: 索引文件太大
问题: 5.4GB Dump 的索引文件约 1.5GB
解决:
1
2
3
4
| # 确保有足够磁盘空间(至少 3 倍堆转储大小)
df -h
# 或将索引放到其他磁盘
|
Q5: 权限不足
错误: Permission denied: mcp__mat__mat_run_command
解决: 在 settings.json 中添加权限:
1
2
3
4
5
| {
"permissions": {
"allow": ["mcp__mat__mat_run_command"]
}
}
|
Q6: 解压结果文件失败 (Windows)
错误: unzip: command not found
解决:
1
2
3
4
5
| # 使用 PowerShell 解压
Expand-Archive heap_dump_172.29.10.122_1774096961008_Query.zip -DestinationPath query_result
# 或使用 7-Zip
& "C:\Program Files\7-Zip\7z.exe" x heap_dump_172.29.10.122_1774096961008_Query.zip -oquery_result
|
附录
A. MAT 内置命令完整列表
| 命令 | 说明 | 参数 |
|---|
histogram | 类直方图 | [class_pattern] |
gc_roots | GC Roots 分析 | [class_pattern] |
path2gc | 追踪到 GC Root | object_id |
thread_overview | 线程概览 | - |
thread_details | 线程详情 | thread_name |
dominator_tree | 支配树 | - |
merge_shortest_paths | 合并最短路径 | object_ids |
collection_fill_ratio | 集合填充率 | - |
find_strings | 查找字符串 | pattern |
system_properties | 系统属性 | - |
component_report | 组件报告 | - |
inspector | 对象检查 | object_id |
show_heap | 显示堆摘要 | - |
B. OQL 语法速查
1
2
3
4
5
6
7
8
9
10
11
| -- 基本查询
SELECT * FROM class_name
-- 条件查询
SELECT f FROM class_name f WHERE condition
-- 字段投影
SELECT f.field1, f.field2 FROM class_name f
-- 像 SQL 一样使用
SELECT toString(f.value) FROM java.lang.String f
|
C. 参考资源
教程版本:v2.0
更新时间:2026-03-23
基于 5.4GB 生产 Heap Dump 分析经验