CMS并发预清理阶段无直接调优参数,由JVM自动触发,旨在减少Remark停顿;其执行需满足老年代使用率超阈值、存在脏卡且CPU空闲;关键调优在于控制晋升、增加并发线程数、降低启动阈值并启用CMSScavengeBeforeRemark。

CMS(Concurrent Mark-Sweep)收集器的并发预清理阶段(Concurrent Preclean)本身不支持直接调优参数,它由 JVM 自动触发和控制,目标是尽量在并发标记结束后、重新标记(Remark)前,把新生代晋升到老年代、或并发期间被修改的老年代对象(即“脏卡”)提前处理掉,从而缩短 Remark 阶段的停顿时间。
理解并发预清理的作用与触发条件
预清理不是独立阶段,而是并发标记(Concurrent Mark)完成后、重新标记(Remark)开始前的一个可选子过程。它只在满足以下条件时才会执行:
- 老年代使用率超过 -XX:CMSInitiatingOccupancyFraction 设定阈值(或通过预测动态触发)
- 并发标记已结束,且存在未处理的“脏卡”(Card Table 中标记为 dirty 的区域)
- 系统有足够空闲 CPU 资源(JVM 会评估并发线程负载)
它本质上是扫描 Card Table,对脏卡对应的卡页(card page)做快速再标记——但仅限于那些能快速判定无需深入遍历的对象(如已回收、或引用关系未变),避免把所有脏卡都拖到 Remark 阶段处理。
间接影响预清理效果的关键调优点
虽然没有 -XX:+UseConcMarkSweepGC 下专用于预清理的开关或阈值,但可通过以下方式提升其效率和价值:
立即学习“Java免费学习笔记(深入)”;
- 降低 Remark 停顿的核心:减少脏卡数量 —— 控制新生代 GC 频率和晋升行为。例如调小 -XX:NewRatio 或增大年轻代(-Xmn),避免频繁 Minor GC 导致大量对象晋升;启用 -XX:+CMSScavengeBeforeRemark(推荐),让 CMS 在 Remark 前强制做一次 Young GC,清掉刚晋升但实际已不可达的对象
- 加快卡表处理速度 —— 增加并发标记线程数:-XX:ConcGCThreads(默认为 ParallelGCThreads / 4,可适当调高,但不宜超过 CPU 核心数的 1/2)
- 让预清理更“愿意”启动 —— 适当降低 -XX:CMSInitiatingOccupancyFraction(如设为 70~75),使并发周期更早开始,为预清理留出更多时间窗口;同时配合 -XX:+UseCMSInitiatingOccupancyOnly 禁用动态阈值预测,增强可预测性
监控预清理是否生效
通过 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 查看 GC 日志,关注类似以下片段:
[CMS-concurrent-preclean: 0.123/0.456 secs]其中 0.123 是实际工作耗时,0.456 是总耗时(含等待)。若该行长期缺失,说明预清理被跳过,常见原因包括:并发标记后脏卡极少、CPU 繁忙、或老年代增长太快直接进入 Remark。
替代思路:当预清理效果有限时
CMS 已在 JDK 9 中被标记为废弃,JDK 14 彻底移除。如果业务仍受限于 CMS 的 Remark 波动,更务实的做法是:
- 升级 JDK,迁移到 G1(开启 -XX:+UseG1GC)或 ZGC(低延迟场景)
- 若必须用 CMS,优先保障 CMSScavengeBeforeRemark 和合理的新老代比例,比纠结预清理参数更有效
- 避免人为“干预”预清理——没有 -XX:+UseCMSPrecleaning 或类似参数,强行添加会被 JVM 忽略
预清理是 CMS 内部的自适应机制,调优重点不在它本身,而在为它创造有利前提:更干净的卡表、更充裕的时间、更可控的晋升节奏。


















