Evacuation Failure 是 G1 GC 复制阶段失败的关键信号,源于对象生命周期、晋升策略与内存布局错配;日志中表现为“Evacuation Failure”字样、长停顿伴低 Survivor 使用率或“to-space exhausted”,主因包括高 MaxTenuringThreshold、不合理 SurvivorRatio、虚拟线程潮及 RegionSize 匹配问题,需通过调低晋升阈值、优化新生代弹性范围等组合策略解决。

Evacuation Failure 是 G1 GC 中一个关键失败信号,不是单纯“空间不够”这么简单,它背后反映的是对象生命周期、晋升策略与内存布局之间的错配。要真正定位并解决,得从日志线索切入,再结合参数逻辑做针对性扩充。
看懂 Evacuation Failure 在日志里的真实含义
它不会直接写成 “Evacuation Failure”,而是藏在 GC 日志的 Cause 字段或括号内,比如:
-
[GC (Evacuation Failure)]—— 明确标识,G1 复制阶段失败 -
[GC (Allocation Failure) ... [G1 Evacuation Pause (young)]]后紧跟着一段长时间停顿(>100ms)且 Survivor 区使用率极低(常低于 5%)—— 隐性信号 - 日志中出现大量
to-space exhausted或evacuation failed字样(JDK 21+ 更倾向用英文提示)
这类日志说明:G1 尝试把 Eden 和部分 Survivor 中存活对象复制到另一个 Survivor(或老年代)时,目标区域没腾出足够连续空间,被迫中止复制流程,转而触发 Full GC 或降级为更重的回收路径。
底层原因不止是 Survivor 太小
单纯调大 Survivor 容量往往治标不治本。真正驱动 Evacuation Failure 的常见组合有:
AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。
- MaxTenuringThreshold 设置过高(如设为 15):对象在 Survivor 区反复 copy 十几次才晋升,导致 Survivor 长期被“占着但不用”,实际可用空间碎片化
- SurvivorRatio 不合理(如 -XX:SurvivorRatio=8,即 Eden:Survivor=8:1):新生代总大小固定时,Survivor 过小,一次 Minor GC 就可能溢出
- 虚拟线程场景下短生命周期对象潮:Spring Boot 3.2 启用 virtual thread 后,Continuation/StackChunk 对象高频创建,Eden 快速填满,Survivor 来不及“消化”就又来一波
- G1RegionSize 与对象大小不匹配:若大量中等对象(如 512KB~1MB)集中分配,可能跨多个 Region,加剧复制时的 to-space 压力
扩充 Survivor 边界的有效做法
不是盲目加参数,而是分步控制变量:
-
先降低晋升阈值:把
-XX:MaxTenuringThreshold=6(默认是 15),让中年对象更快进入老年代,释放 Survivor 压力;观察日志中tenured字段是否稳定增长,而非突增 -
显式调大 Survivor 比例:用
-XX:SurvivorRatio=4(即 Eden 占新生代 1/2,两个 Survivor 合计占 1/2),比默认值更宽松;注意该值只对 Parallel GC 和 ParNew 有效,G1 下需配合-XX:G1NewSizePercent和-XX:G1MaxNewSizePercent控制新生代弹性范围 -
给 G1 新生代留足弹性空间:设置
-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=60,避免 G1 自动收缩新生代导致 Survivor 实际可用空间缩水 -
必要时禁用 Survivor 预留:若确认业务几乎没有中生命周期对象,可加
-XX:-UseAdaptiveSizePolicy+ 手动固定-Xmn,再通过-XX:SurvivorRatio精确切分,消除 JVM 自适应带来的抖动
验证是否真解决问题
改完参数后,重点盯三件事:
- GC 日志中
Evacuation Failure是否消失,G1 Evacuation Pause耗时是否回落至 20ms 以内 - VisualVM 或 JMC 中 Survivor 区利用率是否稳定在 30%~70%,不再长期 95%
- 老年代晋升速率是否平稳——如果突然暴涨,说明对象过早晋升,需回调
MaxTenuringThreshold
不复杂但容易忽略:Evacuation Failure 往往是多个参数共同挤压的结果,单点调整不如建立“Eden 填充节奏 → Survivor 消化能力 → 晋升出口容量”的闭环观察链。

















