启用-xx:+printreferencegc可量化弱引用回收开销,配合printgcdetails等参数能精准定位weakreference在gc中导致缓存失效的问题,日志中“weak: xxx refs”及高占比ref proc耗时是关键证据。

直接启用 -XX:+PrintReferenceGC,配合已有 GC 日志参数,就能准确定位弱引用(尤其是 WeakReference)在每次 GC 中的回收开销——这不是推测,而是日志里可查、可量化的证据。
必须开启的核心 JVM 参数组合
仅靠 -XX:+PrintGCDetails 看不到引用处理细节。要真正“看见”弱引用怎么拖慢接口,得加这一组:
-
-XX:+PrintReferenceGC:强制打印每类引用(Soft/Weak/Phantom/Final)的清理数量和耗时 -
-XX:+PrintGCDetails -XX:+PrintGCDateStamps:对齐时间戳,方便与业务日志(如 getUiToken 调用时间)交叉比对 -
-Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M:确保日志不丢失、可滚动,避免关键片段被覆盖
从日志里识别弱引用“肇事”信号
打开 gc.log,搜索含 Weak 的行。典型有效线索长这样:
[GC Ref Proc: 0.0082134 secs]
[GC Ref Proc: Weak: 1234 refs, 0.0078901 secs]
重点看两处:
- 最后一行中
Weak: XXX refs数值是否异常高(比如单次清理上万弱引用) - 对应
Ref Proc总耗时是否占单次 GC 时间 70% 以上(如上面例子中 0.0079s / 0.0135s ≈ 59%,已属高风险) - 时间戳是否密集出现在接口超时发生前 1–3 秒内(说明 GC 正在阻塞请求线程)
关联业务日志锁定缓存失效源头
弱引用本身不报错,但会导致缓存“凭空消失”。要确认是不是 Caffeine 的 weakKeys() 或 weakValues() 在作祟:
- 在应用日志中搜索 token 缺失、缓存 miss、重建缓存等关键词,记录发生时间
- 拿这些时间点去 gc.log 里查前后 5 秒内的
Weak行 —— 若高度重合,基本可断定是弱引用键/值被提前回收 - 特别注意:如果 key 是临时对象(如方法内 new 出的 String、DTO),又没被其他地方强引用,那 weakKeys() 就等于给它判了“立即死刑”
验证与收口:关掉弱引用再对比
最硬的证据来自对照实验:
- 灰度一台机器,注释掉 Caffeine 构建中的
weakKeys()和weakValues() - 保持其他 JVM 参数和流量不变,运行 30 分钟
- 对比两台机器的 gc.log:
Weak行应归零或极低;同时观察接口 P99 耗时是否回落至正常区间(如从 1024ms → 200ms) - 若回落明显,问题闭环;若无改善,则需排查 PhantomReference 或 SoftReference 等其他引用类型










