Skip to content

ParNew 回收器

ParNew:Serial 的多线程版本

ParNew 是年轻代收集器,本质上是多线程版本的 Serial——使用复制算法,但用多个线程并行执行垃圾回收。

ParNew 的工作原理

Serial(单线程):  ───▶ Eden ──▶ [线程1 标记] ──▶ [线程1 复制] ──▶ 完成

                  │ 停顿时间 = T

ParNew(多线程):  ───▶ Eden ──▶ [线程1+2+3+4 并行] ──▶ 完成

                  │ 停顿时间 ≈ T / N(N = 线程数)

与 Serial 的对比

维度SerialParNew
算法复制复制
线程数单线程多线程(-XX:ParallelGCThreads 控制)
停顿时间短(N 倍加速)
吞吐量
使用场景低配机器Web 服务(CMS 的年轻代)

ParNew 的使用

bash
# ParNew 只能与 CMS 组合使用
java -XX:+UseParNewGC -XX:+UseConcMarkSweepGC MyApp

# 设置并行线程数(默认 = CPU 核心数)
java -XX:+UseParNewGC -XX:ParallelGCThreads=4 MyApp

为什么 ParNew 只能配 CMS

ParNew 专门为 CMS 设计,它和 CMS 的交互非常紧密:

ParNew 年轻代 + CMS 老年代:
┌─────────────────────────────────────────────────┐
│                     年轻代                         │
│  ┌──────────────────────────────────────────┐ │
│  │          ParNew(多线程复制算法)           │ │
│  │  线程数:ParallelGCThreads(默认 = CPU 核数)│ │
│  └──────────────────────────────────────────┘ │
│                        │ 晋升                    │
│                        ▼                        │
│  ┌──────────────────────────────────────────┐ │
│  │              CMS(并发标记清除)            │ │
│  │  老年代收集:大部分与用户线程并发            │ │
│  └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘

ParNew 不能与 Throughput GC(Parallel Old)组合——如果需要多线程年轻代 + 多线程老年代,直接用 Throughput GC(ParallelGC)。

ParNew 的 GC 日志

bash
java -XX:+UseParNewGC \
     -XX:+UseConcMarkSweepGC \
     -XX:+PrintGCDetails \
     MyApp

日志示例:

# ParNew MinorGC(多线程)
2026-03-22T10:00:00.123+0800: [GC (Allocation Failure)
  [ParNew: 20480K->2048K(22528K), 0.0084567 secs]
  20480K->2048K(22528K), 0.0085678 secs]
  [Times: user=0.03 sys=0.01, real=0.01 secs]
#                              ↑
#                          并行 GC 线程的 user 时间累加 > real 时间

日志解读:

  • ParNew:年轻代多线程收集器
  • user=0.03N 个线程的 CPU 时间累加
  • real=0.01:实际墙钟时间(≈ user / N)

ParNew 的参数配置

bash
# 设置年轻代大小(影响 MinorGC 频率)
java -Xmn512m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC MyApp

# 设置 Survivor 比例
java -XX:SurvivorRatio=8 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC MyApp

# 设置并行线程数
java -XX:ParallelGCThreads=8 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC MyApp

# 建议:ParallelGCThreads 不超过 8 个
# 超过 8 个后,线程切换开销可能超过并行收益

ParNew 的优势

1. 停顿时间更短

java
// 场景:年轻代 512MB,单线程 Serial 需要 100ms
// 8 线程 ParNew 只需要约 15ms
// 停顿时间大幅缩短

2. 与 CMS 完美配合

CMS 并发阶段 ──▶ ParNew MinorGC ──▶ CMS 并发阶段
     │                  │
     │ 交替执行          │ 最短停顿
     │                  │
CMS 大部分时间并发,ParNew 停顿时间很短

3. 自适应调节

ParNew 可以和 CMS 共享自适应调节参数:

bash
# 自适应调节年轻代大小
java -XX:+UseAdaptiveSizePolicy \
     -XX:+UseParNewGC \
     -XX:+UseConcMarkSweepGC \
     MyApp

ParNew 的局限性

局限性说明
只能配 CMS不能与 Parallel Old 组合
CPU 密集GC 时消耗所有 CPU 核心
吞吐量不如 ThroughputThroughput GC 专门优化吞吐量
JDK 14 已废弃不再推荐使用

JDK 14 之后:ParNew 的替代

JDK 14 移除了 -XX:+UseParNewGC 选项(CMS 本身也在 JDK 14 中移除)。推荐替代方案:

bash
# 推荐使用 G1(可预测停顿)
java -XX:+UseG1GC MyApp

# 或者 ZGC(超低延迟)
java -XX:+UseZGC MyApp

ParNew vs Throughput 的选择

场景选择原因
低延迟 Web 服务G1CMS 已废弃,G1 是官方推荐
高吞吐批处理Throughput GC专门优化吞吐量
CMS 迁移G1G1 可以替代 CMS
新项目G1 / ZGC不再推荐 ParNew

本节小结

ParNew 收集器的核心要点:

维度说明
本质多线程版本的 Serial(年轻代)
算法复制算法
线程数多线程并行(ParallelGCThreads)
搭档CMS 老年代(唯一组合)
JDK 状态JDK 14 移除
替代方案G1 / ZGC

ParNew 作为 CMS 的年轻代收集器,曾经是低延迟 Web 服务的主流选择。但随着 CMS 的废弃和 G1 的成熟,ParNew 也逐渐退出了历史舞台。

下一节,我们来看 Parallel/Parallel Old 回收器

基于 VitePress 构建