parNew垃圾收集器
ParNew 收集器是 JVM 中针对年轻代的多线程并行收集器,作为 CMS 收集器的黄金搭档,在多核时代扮演着重要角色。ParNew与serial实现基本一致,只是在停顿收集时,是多线程收集。以下是全面剖析:
graph TD
A[ParNew 收集器] --> B[核心特性]
A --> C[工作模式]
A --> D[内存管理]
A --> E[性能特征]
A --> F[调优策略]
B --> B1[多线程并行]
B --> B2[STW 暂停]
B --> B3[复制算法]
C --> C1[多线程标记-复制]
C --> C2[与CMS协同]
D --> D1[分代模型]
D --> D2[卡表技术]
E --> E1[多核优势]
E --> E2[暂停时间]
F --> F1[线程数优化]
F --> F2[空间分配]
一、核心设计定位
1. 历史地位与定位
timeline
title ParNew发展史
section JDK 1.4.2
“ 首次引入 ” : 作为Serial的多线程版本
section JDK 5
“ 成为CMS标配 ” : 年轻代唯一选择
section JDK 9
“ 被G1取代 ” : 不再是默认选项
section JDK 16
“ 仍可启用 ” : 特殊场景使用
2. 架构定位
graph LR
CMS[老年代CMS] --> ParNew[年轻代ParNew]
ParNew --> 优势[完美协同]
优势 --> 停顿协调[GC停顿时间协调]
优势 --> 内存管理[分代策略统一]
优势 --> 卡表共享[共享跨代引用信息]
二、工作模式详解
1. 完整收集流程
sequenceDiagram
App->>JVM: 对象分配请求
JVM->>ParNew: Eden空间不足
ParNew->>所有线程: STW暂停(初始停顿)
loop 多线程并行
ParNew->>ParNew: 标记存活对象
ParNew->>ParNew: 复制到Survivor区
end
ParNew->>所有线程: 恢复运行
2. 多线程并行机制
graph TD
任务划分 --> 分区[堆内存分区]
分区 --> 线程[线程独立工作]
线程 --> 负载均衡[自动负载均衡]
负载均衡 --> 策略[任务窃取机制]
同步 --> 屏障[GC屏障]
屏障 --> 同步点[全局同步点]
三、内存管理机制
1. 分代结构
graph TD
Heap[堆内存] --> Young[年轻代]
Heap --> Old[老年代]
Young --> Eden[Eden区]
Young --> S0[Survivor0]
Young --> S1[Survivor1]
Old --> Tenured[老年代空间]
2. 卡表技术(Card Table)
graph LR
跨代引用 --> 卡表[Card Table]
卡表 --> 字节数组[512字节/卡页]
写屏障 --> 标记[标记脏卡]
标记 --> MinorGC[Minor GC时扫描]
四、性能特征分析
1. 多核加速效果
graph LR
线程数 --> 加速比[性能提升]
单核 --> 基准1x
双核 --> 1.8x
四核 --> 3.2x
八核 --> 5.5x
2. 暂停时间模型
graph TD
暂停时间 --> 因素
因素 --> 堆大小[年轻代大小]
因素 --> 存活率[对象存活率]
因素 --> 线程数[GC线程数]
优化 --> 公式["Tpause = (Syoung * Rlive) / (Ncore * Vcopy)"]
五、关键配置参数
1. 基础启用参数
# 启用ParNew(需配合CMS)
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
2. 核心调优参数
| 参数 | 默认值 | 建议值 | 作用 |
|---|---|---|---|
-XX:ParallelGCThreads | CPU核数 | 等于物理核数 | GC线程数 |
-XX:SurvivorRatio | 8 | 6-10 | Eden/Survivor比例 |
-XX:MaxTenuringThreshold | 15 | 10-15 | 晋升阈值 |
-XX:TargetSurvivorRatio | 50 | 60-80 | Survivor目标利用率 |
六、最佳实践配置
1. 标准配置模板
# 4核服务器配置
java -XX:+UseConcMarkSweepGC \
-XX:+UseParNewGC \
-XX:ParallelGCThreads=4 \
-XX:SurvivorRatio=8 \
-XX:MaxTenuringThreshold=10 \
-Xms4g -Xmx4g \
-jar application.jar
2. 性能优化方向
mindmap
root((优化方向))
减少暂停时间
减小年轻代(-Xmn)
降低存活率(对象池)
提高吞吐量
增加GC线程
增大Eden区
避免晋升
增大Survivor
调整晋升阈值
七、与其它收集器对比
1. 年轻代收集器对比
| 特性 | ParNew | Parallel Scavenge | G1 Young |
|---|---|---|---|
| 算法 | 复制 | 复制 | 复制 |
| 线程 | 并行 | 并行 | 并行 |
| 目标 | 低暂停 | 高吞吐 | 可预测暂停 |
| 协同 | CMS专属 | 独立 | G1统一管理 |
| 适用 | 中小堆 | 大堆 | 超大堆 |
2. 暂停时间对比(4核/2GB堆)
| 收集器 | 平均暂停 | 最大暂停 | 吞吐量 |
|---|---|---|---|
| Serial | 120ms | 250ms | 中等 |
| ParNew | 40ms | 80ms | 高 |
| G1 | 20ms | 50ms | 中高 |
八、现代演进与替代
1. JDK 8+ 的替代方案
graph TD
ParNew --> 局限[年轻代专用]
局限 --> 替代[G1/ZGC统一收集]
替代优势 --> 统一管理[无代际协同问题]
替代优势 --> 算法优化[更先进算法]
替代优势 --> 大堆支持[>32GB堆]
2. 迁移建议
flowchart TD
评估[评估当前系统] --> 特征{特征分析}
特征 -->|暂停敏感| G1[迁移到G1]
特征 -->|大堆>32GB| ZGC[迁移到ZGC]
特征 -->|CMS稳定运行| 保持[保持ParNew+CMS]
九、生产环境案例
1. 电商平台优化案例
graph TD
问题[高峰期GC暂停200ms] --> 分析[诊断工具分析]
分析 --> 原因[年轻代过大]
优化 --> 调整[-Xmn从2G调为1G]
优化 --> 线程[-XX:ParallelGCThreads=16]
结果 --> 提升[暂停降至50ms]
2. 参数调整效果验证
# 调整前
jstat -gcutil <pid> 1000
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 50.00 90.00 60.00 95.00 90.00 100 40.000 5 2.000 42.000
# 调整后
0.00 50.00 80.00 55.00 95.00 90.00 150 30.000 5 2.000 32.000
十、总结结论
-
核心价值:
- CMS 收集器的最佳拍档
- 多核环境下年轻代并行收集最优解
- 低暂停时间的经典实现
-
适用场景:
pie title ParNew适用场景 "4-8核服务器" : 45 "堆<32GB" : 35 "JDK8及以下" : 20 -
迁移建议:
- JDK 8 及以下:继续使用 ParNew+CMS
- JDK 11+:迁移到 G1 或 ZGC
- 新项目:直接采用 ZGC/Shenandoah
最终配置建议:
在 JDK 8 环境中,对于 4-16 核服务器和 4-32GB 堆内存的应用,采用
-XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=N(N=CPU核数)是最佳实践。但对于新项目,建议直接基于 JDK 17+ 使用 ZGC。