时间:2025-12-30 09:18
人气:
作者:admin
gc的老年代内存高居不下,导致最后full gc的发生,我们需要通过分析gc dump文件来解决biggest objects过多的问题

microdnf install -y wget
microdnf install -y procps-ng #包含ps命令
ps -aux # 找到keycloak的pid,默认是712
wget https://github.com/apangin/jattach/releases/download/v2.0/jattach
chmod +x jattach
# 使用jattach执行内存命令
./jattach 712 dumpheap /tmp/heap.hprof

我们可以从biggest objects里面,查看哪些大对象没有被释放,或者频繁被创建
广义概念:程序在某个时间点的状态快照。
| 类型 | 描述 | 常用扩展名 |
|---|---|---|
| Heap Dump | JVM 堆内存快照,包含所有对象实例 | .hprof, .bin, .dmp |
| Thread Dump | 线程状态快照,包含调用栈、锁信息 | .tdump, .txt |
| Core Dump | 进程崩溃时的完整内存镜像 | .core, .dmp |
具体格式:Java 专用的堆转储文件格式。
Dump文件(概念)
├── Heap Dump(堆转储)
│ ├── HProf 格式(标准格式)
│ ├── JProfiler 格式(.snapshot)
│ └── YourKit 格式(.snapshot)
├── Thread Dump(线程转储)
└── Core Dump(核心转储)
# 1. 使用 jmap 命令(最常用)
jmap -dump:format=b,file=heap.hprof <pid>
# 2. 使用 jcmd 命令
jcmd <pid> GC.heap_dump /path/to/heap.hprof
# 3. JVM 启动参数(内存溢出时自动生成)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dumps
# 4. 使用 VisualVM、JConsole 等工具
# 1. 使用 jstack 命令
jstack <pid> > thread.dump
# 2. 使用 jcmd
jcmd <pid> Thread.print > thread.dump
# 3. 发送信号
kill -3 <pid> # 输出到标准输出
文件头
↓
记录类型1 (如:UTF8字符串表)
↓
记录类型2 (如:类加载信息)
↓
记录类型3 (如:实例数据)
↓
记录类型4 (如:对象引用)
↓
...
| 工具 | 特点 | 适用场景 |
|---|---|---|
| Eclipse MAT | 功能强大,内存分析专业 | 深入内存泄漏分析 |
| VisualVM | JDK 自带,轻量级 | 快速查看概览 |
| JProfiler | 商业工具,可视化好 | 性能分析和监控 |
| YourKit | 商业工具,CPU/Memory分析 | 生产环境分析 |
| Java Mission Control | Oracle 官方工具 | Flight Recorder 数据分析 |
# 1. 生成转储文件
jmap -dump:live,format=b,file=keycloak.hprof <pid>
# 2. 用 MAT 打开,常见视图:
- Histogram(直方图): 按类统计对象数量
- Dominator Tree(支配树): 找出内存占用最大的对象
- Leak Suspects(泄漏嫌疑): 自动分析疑似泄漏
- Path to GC Roots(到GC根的路径): 查看对象引用链
// HProf 分析中可能看到:
org.hibernate.engine.query.spi.QueryPlanCache
├── queryPlanCache (ConcurrentHashMap)
│ ├── key: "from User where realmId = ? order by createdTimestamp"
│ ├── value: QueryPlan对象 (包含解析后的SQL、参数映射等)
│ └── size: 可能数千个条目
└── parameterMetadataCache
└── 存储参数元数据
# 1. 只转储存活对象(推荐)
jmap -dump:live,format=b,file=heap.hprof <pid>
# 2. 过滤不需要的内容
# 使用MAT的OQL或过滤器功能
# 3. 压缩存储
jmap -dump:live,format=b,file=heap.hprof.gz <pid>
#!/bin/bash
PID=$(jps | grep keycloak | awk '{print $1}')
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# 生成堆转储
jmap -dump:live,format=b,file=/dump/keycloak_${TIMESTAMP}.hprof $PID
# 生成线程转储
jstack $PID > /dump/thread_${TIMESTAMP}.dump
# 基本分析
echo "=== 堆转储生成完成 ==="
echo "文件: /dump/keycloak_${TIMESTAMP}.hprof"
echo "大小: $(du -h /dump/keycloak_${TIMESTAMP}.hprof | cut -f1)"
总结:HProf 是 Java 堆转储的标准格式文件,属于 Dump 文件的一种。通过分析这种文件,可以定位内存泄漏、优化内存使用,就像你发现的 QueryPlanCache 问题一样。
作者:仓储大叔,张占岭,
荣誉:微软MVP
QQ:853066980
支付宝扫一扫,为大叔打赏!
【从0到1构建一个ClaudeAgent】协作-Agent团队