parallel scavenge 与 cms 完全不兼容,因二者分属hotspot中两套独立代码框架:前者自建调度与调优逻辑,不实现分代框架的协作接口;后者依赖该框架的卡表、写屏障等机制,源码中直接拦截冲突组合并终止初始化。

Parallel Scavenge 与 CMS **完全不兼容**,JVM 启动时会直接报错拒绝加载,不是配置不当的问题,而是底层架构根本无法对话。
为什么硬配会失败?根源在“两个世界”
HotSpot 的垃圾收集器分属两套独立开发的代码框架:
- 分代式 GC 框架:Serial、ParNew、CMS、Serial Old 全部在此框架内,共享卡表更新、写屏障协议、晋升协同逻辑。它们能“互相听懂”——比如 ParNew 在 Minor GC 后会主动通知 CMS 当前晋升了多少对象,以便 CMS 调整并发标记节奏。
-
Parallel Scavenge 独立框架:它从设计之初就绕开上述框架,自建调度、内存分配(如指针碰撞)、自适应调优(
-XX:+UseAdaptiveSizePolicy)和老年代回收(PS MarkSweep)逻辑。它不实现分代框架定义的任何协作接口,CMS 发出的协同信号(如初始标记同步、记忆集刷新)它一律无视。
源码中明确拦截:if (UseParallelGC && UseConcMarkSweepGC) vm_exit_during_initialization()——不是算法冲突,是连握手都做不到。
常见误配现象与快速自查
线上配置看似“写了两个参数”,实际往往隐含冲突:
- 启动日志出现
ParNew但你写了-XX:+UseParallelGC→ 说明同时启用了-XX:+UseConcMarkSweepGC,CMS 自动把新生代切回 ParNew,ParallelGC 被覆盖。 - 报错
Error: Conflicting collector combinations→ 直接删掉-XX:+UseConcMarkSweepGC或所有 CMS 相关参数(如-XX:CMSInitiatingOccupancyFraction)。 - 用 JDK 8u121+ 却手动加
-XX:+UseParallelOldGC→ 该参数已被废弃,加了反而可能触发识别异常。
正确搭配路径:按目标选组合,别强行混搭
没有“通用最强”,只有“目标匹配”:
- 要低延迟(P99 :用
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC(JDK 8),或升级到 G1 / ZGC(JDK 9+ 推荐)。 -
要高吞吐(后台批处理、ETL、长周期计算):必须成对使用
-XX:+UseParallelGC -XX:+UseParallelOldGC(JDK 8 默认),禁用所有 CMS 参数。 - 想兼顾分代与低延迟又用新 JDK:G1 是唯一官方支持的替代方案,它自身管理整堆,不依赖新生代/老年代收集器搭配。
一个容易被忽略的关键细节
Parallel Scavenge 的 -XX:MaxGCPauseMillis 是软目标,设得太激进(如 50ms)会导致 GC 频次暴增、吞吐暴跌;而 CMS 的停顿时间不可控,尤其在并发失败触发 Full GC 时。两者目标本身就矛盾——一个靠频繁小停顿保响应,一个靠减少总停顿时间保吞吐。强行拉郎配,等于让赛车手和货运司机共用一辆车的方向盘。











