-XX:+PrintReferenceGC是定位软/弱引用引发GC耗时飙升最有效的手段,它能在GC日志中明确显示Soft/Weak/Phantom/FinalReference各自的处理耗时,无需代码改动或问题复现。

直接看 -XX:+PrintReferenceGC 日志,是定位软/弱引用引发 GC 耗时飙升最有效的手段之一。它不依赖代码改动,也不需要复现问题,只要开启就能在 GC 日志里明确看到哪类引用在拖慢回收过程。
为什么必须加这个参数?
默认 GC 日志只显示“用了多久”,但不会告诉你“时间花在哪”。比如一次 Young GC 耗时 800ms,其中 750ms 花在 Ref Proc 阶段——这个阶段就是处理软、弱、虚、Final 引用的。没有 -XX:+PrintReferenceGC,你只能猜;加上后,日志会逐行标明:
→ SoftReference 处理耗时 XX ms
→ WeakReference 处理耗时 XX ms
→ PhantomReference 处理耗时 XX ms
→ FinalReference 处理耗时 XX ms
这样就能一眼锁定瓶颈类型。
怎么配置并验证生效?
在 JVM 启动参数中加入:-XX:+PrintReferenceGC -XX:+PrintGCDetails -Xloggc:/path/to/gc.log
上线运行一段时间(建议至少覆盖 10 次以上 GC),然后用 gcViewer 或文本工具搜索日志中的 SoftReference、WeakReference 关键字。如果看到类似以下内容,说明已生效:
SoftReference 2456 refs, 12.4 msWeakReference 8921 refs, 386.7 msPhantomReference 15 refs, 0.2 ms
注意:WeakReference 耗时高,往往意味着大量对象正被快速淘汰(比如缓存 key 是 WeakReference 的 WeakHashMap),且队列积压未及时清空;SoftReference 耗时高,则多见于大缓存场景,JVM 在内存压力下批量清理软引用对象,序列化/反序列化或回调逻辑可能隐含开销。
结合业务代码快速定位源头
看到 WeakReference 耗时突增后,重点排查三类常见模式:
- 使用
WeakHashMap作为缓存容器,且 value 持有大对象或未及时 remove - 自定义缓存封装中,key 或 value 封装了
WeakReference<T>,但未配合ReferenceQueue做异步清理 - 第三方库(如某些 ORM、连接池、动态代理框架)内部使用了弱引用机制,升级版本或调整配置可缓解(例如 HikariCP 的
leakDetectionThreshold关闭后可能减少 WeakReference 创建)
软引用同理,重点查 SoftReference<byte[]> 类型的大缓冲区、图片/模板缓存等。这类对象不会立刻被回收,但会在多次 GC 后集中清理,容易造成某次 GC 突然变慢。
不是加了就完事:关键后续动作
日志确认是 Weak/Soft 引用导致耗时高之后,不能只调 JVM 参数。真正有效的是:
- 检查对应引用是否真的必要——很多场景用普通 HashMap + 显式过期策略更可控
- 若必须用弱/软引用,确保配套
ReferenceQueue并启动清理线程,避免引用对象堆积 - 对软引用缓存,限制最大数量或大小(如
new SoftReference<>(data, queue)后做容量控制) - 观察
-XX:+PrintTenuringDistribution输出,确认这些引用关联的对象是否频繁晋升到老年代,加剧 Mixed GC 压力
不复杂但容易忽略:PrintReferenceGC 是打开引用级 GC 诊断的钥匙,但它只是起点,不是解法。

















