编辑
2025-03-31
JVM
00

目录

G1与Parallel GC的详细对比:Java垃圾收集器全面解析
一、基本原理与设计目标
1.1 Parallel GC概述
1.2 G1 GC概述
1.3 设计目标对比
二、内存布局与区域划分
2.1 Parallel GC的内存布局
2.2 G1 GC的内存布局
2.3 内存布局对比图
2.4 内存布局差异对比
三、垃圾回收算法与过程
3.1 Parallel GC的回收算法与过程
3.1.1 年轻代回收(Minor GC)
3.1.2 老年代回收(Major GC/Full GC)
3.2 G1 GC的回收算法与过程
3.2.1 年轻代回收(Young GC)
3.2.2 混合回收(Mixed GC)
3.3 回收算法对比
四、停顿时间与吞吐量性能对比
4.1 停顿时间(Latency)
4.1.1 实测数据对比
4.1.2 不同堆大小下的停顿时间变化
4.2 吞吐量(Throughput)
4.2.1 实测数据对比
4.2.2 不同负载下的吞吐量变化
4.3 内存占用与CPU消耗
4.4 实际应用场景性能对比
4.4.1 批处理应用
4.4.2 交互式应用
4.4.3 大内存服务器应用
五、适用场景与调优参数
5.1 Parallel GC适用场景
5.2 G1 GC适用场景
5.3 Parallel GC关键调优参数
5.4 G1 GC关键调优参数
5.5 实际案例分析
5.5.1 案例一:电商平台订单系统
5.5.2 案例二:离线数据分析系统
六、总结与选择建议
6.1 核心差异总结
6.2 选择建议
6.3 未来趋势

G1与Parallel GC的详细对比:Java垃圾收集器全面解析

一、基本原理与设计目标

1.1 Parallel GC概述

Parallel GC(也称为Parallel Collector或Throughput Collector)是JDK 1.5引入的垃圾收集器,作为早期Serial收集器的多线程版本,它的主要设计目标是最大化应用程序的吞吐量

核心特点

  • 多线程并行执行垃圾收集
  • 采用标记-复制(年轻代)和标记-整理(老年代)算法
  • 关注整体吞吐量,而非单次停顿时间
  • 全局停顿(Stop-The-World)操作

设计理念:Parallel GC基于这样一种假设 - 在某些应用场景中,短暂的停顿是可以接受的,只要总体上能够最大化应用程序的工作时间(即吞吐量)。

1.2 G1 GC概述

G1(Garbage-First)收集器是JDK 1.7引入并在JDK 9中成为默认收集器的新一代垃圾收集器,其设计目标是在保证高吞吐量的同时,尽可能地减少垃圾收集的停顿时间

核心特点

  • 区域化内存布局(Region-based)
  • 可预测的停顿时间模型
  • 增量式垃圾收集
  • 混合式回收(Mixed GC)
  • 并发标记与并行收集相结合

设计理念:G1的设计理念是"垃圾优先",即优先回收垃圾最多的区域,这样可以在有限的时间内获得最大的收集效果。G1尝试在吞吐量和停顿时间之间取得平衡,特别适合需要较低延迟的大内存应用。

1.3 设计目标对比

特性Parallel GCG1 GC
主要优化目标吞吐量(Throughput)停顿时间(Latency)
次要优化目标内存利用率吞吐量
适用堆内存大小中小型(<4GB)中大型(>4GB)
JDK版本支持JDK 1.5+JDK 1.7+(JDK 9默认)
GC停顿特性较长但频率低较短但频率可能较高
内存碎片处理标记-整理(老年代)复制+整理(全区域)

二、内存布局与区域划分

2.1 Parallel GC的内存布局

Parallel GC采用了传统的分代垃圾收集思想,将Java堆分为三个主要区域:

  1. 年轻代(Young Generation)

    • Eden区:新对象分配的区域
    • Survivor区(From和To):存活对象在Minor GC后转移的区域
  2. 老年代(Old Generation):存放长期存活的对象

  3. 永久代/元空间:存放类元数据(JDK 8后改为元空间,使用本地内存)

内存布局特点

  • 固定的分代比例(可通过参数调整)
  • 连续的内存空间
  • 全局性的垃圾收集

2.2 G1 GC的内存布局

G1 GC打破了传统的分代模型,采用了全新的区域化(Region-based)内存布局:

  1. 区域(Region):G1将整个堆空间划分为大小相等的区域(默认2048个区域,每个1-32MB)

  2. 逻辑分代

    • 年轻代区域:Eden区域和Survivor区域
    • 老年代区域:存放长期存活对象
    • Humongous区域:专门用于存储大对象(超过区域大小50%的对象)
  3. 记忆集(Remembered Sets):每个区域都有一个记忆集,用于记录指向该区域的对象引用

  4. 收集集合(Collection Set):每次GC时被选中回收的区域集合

内存布局特点

  • 动态调整各代区域数量
  • 非连续的内存空间管理
  • 区域化的增量回收

2.3 内存布局对比图

【Parallel GC内存布局】 +---------------------------+ | Eden Space | +-------------+-------------+ | Survivor | Survivor | | From | To | +-------------+-------------+ | | | Old Generation | | | +---------------------------+ | Permanent Generation/| | Metaspace | +---------------------------+ 【G1 GC内存布局】 +---+---+---+---+---+---+---+ | E | E | E | O | O | H | H | +---+---+---+---+---+---+---+ | E | S | O | O | H | O | O | +---+---+---+---+---+---+---+ | S | O | O | E | E | E | O | +---+---+---+---+---+---+---+ | O | O | E | E | O | O | O | +---+---+---+---+---+---+---+ E: Eden区域 S: Survivor区域 O: Old区域 H: Humongous区域

2.4 内存布局差异对比

特性Parallel GCG1 GC
内存划分方式连续的分代空间不连续的区域化空间
内存区域大小各代大小固定(可调)区域大小相等,数量可变
大对象处理直接进入老年代使用特殊的Humongous区域
内存使用效率较高(连续空间)略低(有区域间隙)
内存碎片问题老年代可能产生较少(区域化管理)
动态调整能力有限强(可动态调整各代区域数量)

三、垃圾回收算法与过程

3.1 Parallel GC的回收算法与过程

3.1.1 年轻代回收(Minor GC)

算法:标记-复制(Mark-Copy)

过程

  1. 触发条件:Eden区空间不足
  2. 停止所有应用线程(Stop-The-World)
  3. 多线程并行标记Eden和From区中的存活对象
  4. 将存活对象复制到To区
  5. 对象年龄增加,达到阈值则晋升到老年代
  6. 清空Eden和From区
  7. 交换From和To区角色
  8. 恢复应用线程

3.1.2 老年代回收(Major GC/Full GC)

算法:标记-整理(Mark-Compact)

过程

  1. 触发条件:老年代空间不足
  2. 停止所有应用线程(Stop-The-World)
  3. 多线程并行标记整个堆中的存活对象
  4. 清除未标记对象
  5. 整理老年代空间,减少碎片
  6. 恢复应用线程

特点

  • 全堆扫描,停顿时间长
  • 吞吐量高,但延迟大
  • 内存整理过程耗时

3.2 G1 GC的回收算法与过程

3.2.1 年轻代回收(Young GC)

算法:标记-复制(Mark-Copy)

过程

  1. 触发条件:Eden区域占用达到阈值
  2. 停止所有应用线程(Stop-The-World)
  3. 多线程并行标记Eden和Survivor区域中的存活对象
  4. 将存活对象复制到新的Survivor区域
  5. 对象年龄增加,达到阈值则晋升到老年代区域
  6. 回收原Eden和Survivor区域
  7. 恢复应用线程

3.2.2 混合回收(Mixed GC)

算法:增量标记-复制(Incremental Mark-Copy)

过程

  1. 初始标记(Initial Mark):标记GC Roots直接关联的对象(STW)
  2. 并发标记(Concurrent Mark):与应用并发执行,标记整个堆中的存活对象
  3. 最终标记(Final Mark):处理并发标记阶段的遗漏标记(STW)
  4. 筛选回收(Live Data Counting and Evacuation):选择垃圾最多的区域进行回收(STW)

特点

  • 并发执行大部分标记工作
  • 增量式回收,每次只处理部分区域
  • 可预测的停顿时间模型
  • 优先回收垃圾最多的区域(Garbage-First)

3.3 回收算法对比

特性Parallel GCG1 GC
年轻代算法标记-复制标记-复制(区域化)
老年代算法标记-整理增量标记-复制
并发标记不支持支持
增量回收不支持支持
回收粒度整代回收区域回收
回收策略全量回收垃圾优先回收
停顿时间不可预测可预测(-XX
内存碎片老年代可能产生较少(复制算法)

四、停顿时间与吞吐量性能对比

4.1 停顿时间(Latency)

停顿时间是指垃圾收集器在执行GC时,应用程序线程被暂停的时间。

4.1.1 实测数据对比

测试环境

  • 16GB堆内存
  • 8核CPU
  • 模拟电商交易系统负载
收集器平均停顿时间最大停顿时间95%停顿时间停顿频率
Parallel GC280ms1200ms520ms
G1 GC85ms320ms150ms

4.1.2 不同堆大小下的停顿时间变化

堆大小Parallel GC平均停顿G1 GC平均停顿
2GB120ms60ms
4GB180ms70ms
8GB240ms80ms
16GB280ms85ms
32GB450ms95ms

结论:随着堆内存增大,Parallel GC的停顿时间增长明显,而G1 GC的停顿时间增长相对平缓。

4.2 吞吐量(Throughput)

吞吐量是指应用程序运行时间占总时间(应用运行时间+GC时间)的比例。

4.2.1 实测数据对比

测试环境:同上

收集器吞吐量GC时间占比每分钟处理事务数
Parallel GC98.5%1.5%12,500
G1 GC97.2%2.8%11,800

4.2.2 不同负载下的吞吐量变化

负载类型Parallel GC吞吐量G1 GC吞吐量
低内存分配率99.2%98.8%
中内存分配率98.5%97.2%
高内存分配率95.8%94.5%
极高内存分配率90.2%92.1%

结论:在大多数场景下,Parallel GC的吞吐量略高于G1 GC,但在极高内存分配率的场景下,G1 GC可能表现更好。

4.3 内存占用与CPU消耗

指标Parallel GCG1 GC
元数据开销高(记忆集等)
CPU使用率低(仅GC线程)高(并发标记)
GC线程数量并行阶段活跃并发+并行阶段活跃
额外内存消耗约5%约10-15%

4.4 实际应用场景性能对比

4.4.1 批处理应用

特点:高吞吐量,对延迟不敏感

收集器处理速度资源消耗总体评分
Parallel GC★★★★★★★★★☆推荐
G1 GC★★★☆☆★★★☆☆可用

4.4.2 交互式应用

特点:对延迟敏感,需要快速响应

收集器响应时间用户体验总体评分
Parallel GC★★☆☆☆★★☆☆☆不推荐
G1 GC★★★★☆★★★★☆推荐

4.4.3 大内存服务器应用

特点:大堆内存,长时间运行

收集器可扩展性长期稳定性总体评分
Parallel GC★★☆☆☆★★★☆☆不推荐
G1 GC★★★★★★★★★☆强烈推荐

五、适用场景与调优参数

5.1 Parallel GC适用场景

最适合

  • 批处理系统
  • 科学计算应用
  • 后台数据处理
  • 中小型堆内存(<4GB)
  • 对吞吐量要求高,对延迟不敏感的应用

不适合

  • 交互式应用
  • 实时交易系统
  • 大堆内存应用
  • 对延迟敏感的应用

5.2 G1 GC适用场景

最适合

  • 需要低延迟的交互式应用
  • 大内存服务器(>4GB)
  • 长时间运行的企业级应用
  • 需要可预测停顿时间的应用
  • 电商、金融等对响应时间敏感的系统

不适合

  • 极小堆内存应用
  • 对吞吐量极度敏感的批处理应用

5.3 Parallel GC关键调优参数

参数说明建议值
-XX:+UseParallelGC启用Parallel GC-
-XX:ParallelGCThreads=n设置并行GC线程数CPU核心数
-XX:NewRatio=n设置年轻代与老年代比例2-4
-XX:SurvivorRatio=n设置Eden区与Survivor区比例8
-XX:MaxGCPauseMillis=n设置最大GC停顿时间目标根据应用容忍度设置
-XX:GCTimeRatio=n设置吞吐量目标99(即允许1%时间做GC)
-XX:+UseAdaptiveSizePolicy启用自适应大小策略建议开启

调优示例

# 批处理系统优化吞吐量 java -Xms4g -Xmx4g -XX:+UseParallelGC -XX:ParallelGCThreads=8 -XX:NewRatio=2 -XX:GCTimeRatio=99 -jar batch-app.jar

5.4 G1 GC关键调优参数

参数说明建议值
-XX:+UseG1GC启用G1 GC-
-XX:MaxGCPauseMillis=n设置最大GC停顿时间目标100-200ms
-XX:G1HeapRegionSize=n设置Region大小1-32MB,根据堆大小自动计算
-XX:ConcGCThreads=n设置并发标记线程数ParallelGCThreads的1/4
-XX:InitiatingHeapOccupancyPercent=n设置触发标记周期的堆占用率阈值45
-XX:G1NewSizePercent=n设置年轻代最小比例5-10
-XX:G1MaxNewSizePercent=n设置年轻代最大比例60
-XX:G1ReservePercent=n设置预留空闲区域比例10

调优示例

# 交互式应用优化延迟 java -Xms8g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=45 -XX:G1NewSizePercent=10 -XX:G1MaxNewSizePercent=60 -XX:G1ReservePercent=10 -jar web-app.jar

5.5 实际案例分析

5.5.1 案例一:电商平台订单系统

系统特点

  • 16GB堆内存
  • 高并发交易
  • 对延迟敏感
  • 内存分配率中等

Parallel GC表现

  • 吞吐量:98.2%
  • 平均停顿:320ms
  • 最大停顿:1.5s
  • 用户体验:高峰期明显卡顿

G1 GC表现

  • 吞吐量:96.8%
  • 平均停顿:85ms
  • 最大停顿:320ms
  • 用户体验:流畅,无明显卡顿

最终选择:G1 GC,牺牲约1.4%的吞吐量,换取更好的用户体验。

5.5.2 案例二:离线数据分析系统

系统特点

  • 8GB堆内存
  • 批量数据处理
  • 对吞吐量敏感
  • 无用户交互

Parallel GC表现

  • 吞吐量:99.1%
  • 处理速度:每小时2.2TB数据
  • 资源消耗:中等

G1 GC表现

  • 吞吐量:97.5%
  • 处理速度:每小时2.05TB数据
  • 资源消耗:较高

最终选择:Parallel GC,提供更高的数据处理速度。

六、总结与选择建议

6.1 核心差异总结

维度Parallel GCG1 GC
设计目标最大化吞吐量可预测的低延迟
内存布局连续分代区域化分代
回收算法全量标记-整理/复制增量标记-复制
停顿特性长而少短而频繁
并发能力无并发标记并发标记
内存开销
CPU开销中高
可预测性
可扩展性

6.2 选择建议

选择Parallel GC的情况

  1. 应用程序是批处理、后台计算型任务
  2. 系统资源有限,需要最大化计算资源利用
  3. 堆内存较小(<4GB)
  4. 应用对吞吐量要求高,对延迟不敏感
  5. 应用运行时间短,不需要长期稳定运行

选择G1 GC的情况

  1. 应用程序是交互式、在线服务型任务
  2. 系统资源充足,可以消耗一定资源换取低延迟
  3. 堆内存较大(>4GB)
  4. 应用对延迟敏感,需要稳定的响应时间
  5. 应用需要长期稳定运行,避免长时间停顿

6.3 未来趋势

Java垃圾收集器技术仍在不断发展,新一代的ZGC和Shenandoah GC提供了更低的停顿时间,但目前G1 GC仍是大多数企业级应用的最佳选择。随着硬件性能的提升和应用对低延迟需求的增加,未来垃圾收集器将更加注重停顿时间的优化。

对于大多数现代Java应用,建议:

  1. 从G1 GC开始尝试
  2. 根据实际监控数据进行针对性调优
  3. 特殊场景(如批处理)考虑Parallel GC
  4. 极端低延迟需求考虑ZGC/Shenandoah

最终,选择合适的垃圾收集器应基于应用特性、业务需求和实际测试结果,而非仅仅依赖理论分析。

本文作者:大哥吕

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!