parallel scavenge与parallel old是吞吐量优先的并行回收组合,采用多线程stw机制,通过接受较少但稍长的停顿来最大化用户代码执行时间;需正确搭配、显式启用、设定吞吐目标并匹配cpu密集型后台场景。

Parallel Scavenge 和 Parallel Old 是一套以吞吐量优先为目标的垃圾回收组合,提升吞吐量的关键不在于“减少 GC 次数”或“消除停顿”,而在于让 JVM 在单位总时间中,尽可能多地运行用户代码。它的设计逻辑是:接受稍长但更少的 STW 停顿,换取更高的整体执行效率。
用对组合,确保老年代不拖后腿
Parallel Scavenge 只负责新生代,必须搭配 Parallel Old 才能形成完整的并行吞吐方案。如果错误搭配 Serial Old(尤其在 JDK 8 之后),老年代回收会退化为单线程,成为瓶颈,大幅拉低吞吐量。
- 显式启用组合:添加 -XX:+UseParallelGC -XX:+UseParallelOldGC(JDK 8 默认已启用,但显式声明可避免环境差异干扰)
- 禁用不兼容组合:确保未启用 -XX:+UseSerialGC 或残留 CMS 相关参数
- 验证实际生效:启动时加 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,日志中应出现 PSYoungGen(Parallel Scavenge)和 ParOldGen(Parallel Old)字样
设定明确的吞吐目标,交给自适应策略优化
Parallel 系列的核心优势是自适应调节(-XX:+UseAdaptiveSizePolicy),它会动态调整 Eden/Survivor 比例、晋升阈值、堆各区域大小等,无需手动微调。你只需告诉 JVM 你最在意什么:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 更看重吞吐量百分比?用 -XX:GCTimeRatio=19(默认值,表示 GC 时间占总时间 ≤ 1/20,即吞吐量 ≥ 95%);数值越大,越倾向压缩 GC 时间,提高吞吐
- 更关注单次停顿上限?用 -XX:MaxGCPauseMillis=200(例如设为 200ms),但注意:设得太小会导致 GC 更频繁、年轻代变小、对象过早晋升,反而降低吞吐——这不是低延迟收集器,强行压停顿会适得其反
- 两项不要同时设置:它们目标冲突,JVM 会优先满足 MaxGCPauseMillis,可能牺牲吞吐目标
合理分配硬件资源,让并行真正并起来
Parallel 收集器依赖多线程并行工作,线程数不足或过剩都会影响效率:
- 默认 GC 线程数 ≈ CPU 核心数;若应用本身已密集占用 CPU,可略减:如 16 核机器上设 -XX:ParallelGCThreads=12
- 避免过度分配:线程数远超物理核心,反而引发上下文切换开销,降低有效吞吐
- 确保堆内存足够:吞吐量高意味着对象生命周期可能拉长,-Xmx 和 -Xms 设为相同值可避免扩容抖动,稳定吞吐表现
匹配适用场景,不硬套在错的地方
这套组合不是万能的。它在以下情况才能真正发挥吞吐优势:
- 任务是 CPU 密集型、后台批处理类(如报表生成、批量订单结算、科学计算)
- 应用无强交互需求,能容忍几百毫秒级的 STW(比如非实时交易系统)
- 部署在多核服务器环境(至少 4 核以上),且未被其他高负载进程严重争抢 CPU
- 对象创建快、死亡也快(符合分代假说),这样 Parallel Scavenge 的复制算法效率最高
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










