年轻代“假死”是AdaptiveSizePolicy错误压缩Survivor空间致tenuring threshold强制为1,引发YGC频发、对象直升老年代;可通过GC日志、jstat、jmap定位,并以禁用自适应、固定年轻代大小、设定SurvivorRatio和MaxTenuringThreshold修复。

年轻代“假死”通常表现为:应用响应变慢、接口超时、YGC 频率陡增但每次回收量极低,Eden 区刚填满就触发 GC,Survivor 区几乎不存对象,大量对象直接晋升老年代——这正是 AdaptiveSizePolicy 在错误时机大幅压缩 Survivor 空间、把 tenuring threshold 强制压到 1 所致。
看日志确认晋升异常是否由 AdaptiveSizePolicy 触发
启动时加上关键参数,捕获策略干预痕迹:
-XX:+PrintGCDetails -XX:+PrintAdaptiveSizePolicy -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -Xlog:gc+age=debug- 重点搜索日志中是否出现:
Desired survivor size反复重设、tenuring threshold: 1、AdaptiveSizePolicy::compute_eden_size显著缩小 Survivor、AdaptiveSizePolicy::update_eden_size中survivor size持续低于 2MB(如survivor size: 1048576) - 若看到类似
AdaptiveSizePolicy::compute_generation_sizes: requested young gen size: ...后紧跟着tenuring threshold forced to 1,基本可锁定是 AdaptiveSizePolicy 主动降级晋升年龄
用 jstat 实时验证 Survivor 容量抖动与晋升失衡
执行 jstat -gc 每秒刷新,重点关注三列:
-
S0C/S1C:持续在 1–4MB 之间跳变(如从 8MB → 2MB → 1MB),说明 Survivor 被反复压缩 -
EC:同步膨胀(如 512MB → 900MB),反映 Eden 被拉大以“缓解 GC 频率”,实则恶化问题 -
YGC和YGCT:YGC 次数飙升(>10次/秒),但YU(Young Used)回收后仍接近 EC,说明存活对象没进 Survivor,全被“踢”去老年代
结合 jmap 快照定位对象去向
当 YGC 高频发生时,立即执行:
-
jmap -histo:live:查看是否大量短期对象(如 byte[]、StringBuilder、临时 DTO)出现在 top 10,且类名带明显业务特征| head -20 -
jmap -heap:检查输出中PSYoungGeneration下的FromSpace和ToSpace容量是否远小于预期(比如设置-XX:SurvivorRatio=8,但实际 S0C/S1C 只有 1MB,而 EC 达 1GB) - 若发现
PSOldGeneration的used在 YGC 后快速上涨(如每秒 +50MB),而OC(Old Capacity)未变,说明对象正批量提前晋升
快速止血与长期修复
不是调参,而是夺回控制权:
- 立即加参关闭自适应:
-XX:-UseAdaptiveSizePolicy - 显式固定年轻代大小:
-Xmn512m(根据压测结果定,避免过小) - 强制 Survivor 比例生效:
-XX:SurvivorRatio=8(确保 Eden:S0:S1 = 8:1:1) - 限制最大晋升年龄防止误判:
-XX:MaxTenuringThreshold=6(比默认 15 更保守,留出缓冲) - 补充观察项:加
-XX:+PrintTenuringDistribution,确认每次 YGC 后各年龄对象分布是否稳定










