cms重标记阶段通过聚焦并发标记期间的引用变动(如跨代引用、dirty card)实现高效stw扫描;优化手段包括强制前置minor gc、控制eden填充节奏(cmsscheduleremarkedensizethreshold/edenpenetration)、限制abortable preclean时长(cmsmaxabortableprecleantime)及减少跨代强引用。

CMS 重标记(Remark)阶段是整个 GC 周期中 STW 时间最长、最易成为性能瓶颈的环节。它不从 GC Roots 全量重扫,而是聚焦于并发标记期间被用户线程修改过的对象——尤其是跨代引用(如新生代对象对老年代的引用)和卡表(Card Table)中标记为 Dirty 的区域。优化目标明确:减少扫描范围、压缩停顿窗口、降低并发干扰。
强制前置 Minor GC
这是最直接有效的优化手段。启用 -XX:+CMSScavengeBeforeRemark,让 CMS 在进入 Remark 前主动触发一次新生代回收。此举能清理掉大量已不可达的年轻代对象,显著减少 Remark 阶段需扫描的“年轻代 → 老年代”引用数量。实测中,200ms+ 的停顿常可压至 20ms 内。
控制 Eden 区填充节奏
避免 Remark 时 Eden 已接近满载,否则 Minor GC 可能来不及完成,导致 Remark 扫描压力陡增。配合以下参数协同调控:
- -XX:CMSScheduleRemarkEdenSizeThreshold:设定触发预清理的 Eden 容量阈值(默认 2MB)
- -XX:CMSScheduleRemarkEdenPenetration:设定 Eden 使用率阈值(默认 50%),达此比例即启动预清理
二者共同作用,使预清理更早介入,为 Remark 争取更干净的年轻代状态。
限制预清理时长,保障确定性
可终止的预清理(Abortable Preclean)本意是分担 Remark 工作,但若等待 Minor GC 过久,反而拖长整体延迟。通过 -XX:CMSMaxAbortablePrecleanTime=5000(单位毫秒)设上限,超时即结束并进入 Remark,避免不确定性等待。
减少跨代强引用污染
业务代码中应避免老年代对象长期持有新生代新创建对象的强引用(例如缓存中直接存 DTO 实例)。这类引用会持续污染卡表,放大 Remark 扫描负担。建议用弱引用、软引用,或确保引用生命周期与代际匹配。
监控与调优依据
关键日志指标必须关注:
- remark time:直接反映 STW 时长
- preclean time:若占比过高,说明卡表脏页过多,需检查跨代引用模式
- 晋升速率与老年代占用趋势:辅助判断 -XX:CMSInitiatingOccupancyFraction 是否合理(推荐初始设为 70)
参数调优有边界,根本解法在于降低对象图动态性——比如减少短命对象晋升、拆分大缓存、避免静态集合无节制增长。











