Parallel GC(也称为Parallel Collector或Throughput Collector)是JDK 1.5引入的垃圾收集器,作为早期Serial收集器的多线程版本,它的主要设计目标是最大化应用程序的吞吐量。
核心特点:
设计理念:Parallel GC基于这样一种假设 - 在某些应用场景中,短暂的停顿是可以接受的,只要总体上能够最大化应用程序的工作时间(即吞吐量)。
G1(Garbage-First)收集器是JDK 1.7引入并在JDK 9中成为默认收集器的新一代垃圾收集器,其设计目标是在保证高吞吐量的同时,尽可能地减少垃圾收集的停顿时间。
核心特点:
设计理念:G1的设计理念是"垃圾优先",即优先回收垃圾最多的区域,这样可以在有限的时间内获得最大的收集效果。G1尝试在吞吐量和停顿时间之间取得平衡,特别适合需要较低延迟的大内存应用。
特性 | Parallel GC | G1 GC |
---|---|---|
主要优化目标 | 吞吐量(Throughput) | 停顿时间(Latency) |
次要优化目标 | 内存利用率 | 吞吐量 |
适用堆内存大小 | 中小型(<4GB) | 中大型(>4GB) |
JDK版本支持 | JDK 1.5+ | JDK 1.7+(JDK 9默认) |
GC停顿特性 | 较长但频率低 | 较短但频率可能较高 |
内存碎片处理 | 标记-整理(老年代) | 复制+整理(全区域) |
Parallel GC采用了传统的分代垃圾收集思想,将Java堆分为三个主要区域:
年轻代(Young Generation)
老年代(Old Generation):存放长期存活的对象
永久代/元空间:存放类元数据(JDK 8后改为元空间,使用本地内存)
内存布局特点:
G1 GC打破了传统的分代模型,采用了全新的区域化(Region-based)内存布局:
区域(Region):G1将整个堆空间划分为大小相等的区域(默认2048个区域,每个1-32MB)
逻辑分代:
记忆集(Remembered Sets):每个区域都有一个记忆集,用于记录指向该区域的对象引用
收集集合(Collection Set):每次GC时被选中回收的区域集合
内存布局特点:
【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区域
特性 | Parallel GC | G1 GC |
---|---|---|
内存划分方式 | 连续的分代空间 | 不连续的区域化空间 |
内存区域大小 | 各代大小固定(可调) | 区域大小相等,数量可变 |
大对象处理 | 直接进入老年代 | 使用特殊的Humongous区域 |
内存使用效率 | 较高(连续空间) | 略低(有区域间隙) |
内存碎片问题 | 老年代可能产生 | 较少(区域化管理) |
动态调整能力 | 有限 | 强(可动态调整各代区域数量) |
算法:标记-复制(Mark-Copy)
过程:
算法:标记-整理(Mark-Compact)
过程:
特点:
算法:标记-复制(Mark-Copy)
过程:
算法:增量标记-复制(Incremental Mark-Copy)
过程:
特点:
特性 | Parallel GC | G1 GC |
---|---|---|
年轻代算法 | 标记-复制 | 标记-复制(区域化) |
老年代算法 | 标记-整理 | 增量标记-复制 |
并发标记 | 不支持 | 支持 |
增量回收 | 不支持 | 支持 |
回收粒度 | 整代回收 | 区域回收 |
回收策略 | 全量回收 | 垃圾优先回收 |
停顿时间 | 不可预测 | 可预测(-XX) |
内存碎片 | 老年代可能产生 | 较少(复制算法) |
停顿时间是指垃圾收集器在执行GC时,应用程序线程被暂停的时间。
测试环境:
收集器 | 平均停顿时间 | 最大停顿时间 | 95%停顿时间 | 停顿频率 |
---|---|---|---|---|
Parallel GC | 280ms | 1200ms | 520ms | 低 |
G1 GC | 85ms | 320ms | 150ms | 中 |
堆大小 | Parallel GC平均停顿 | G1 GC平均停顿 |
---|---|---|
2GB | 120ms | 60ms |
4GB | 180ms | 70ms |
8GB | 240ms | 80ms |
16GB | 280ms | 85ms |
32GB | 450ms | 95ms |
结论:随着堆内存增大,Parallel GC的停顿时间增长明显,而G1 GC的停顿时间增长相对平缓。
吞吐量是指应用程序运行时间占总时间(应用运行时间+GC时间)的比例。
测试环境:同上
收集器 | 吞吐量 | GC时间占比 | 每分钟处理事务数 |
---|---|---|---|
Parallel GC | 98.5% | 1.5% | 12,500 |
G1 GC | 97.2% | 2.8% | 11,800 |
负载类型 | 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可能表现更好。
指标 | Parallel GC | G1 GC |
---|---|---|
元数据开销 | 低 | 高(记忆集等) |
CPU使用率 | 低(仅GC线程) | 高(并发标记) |
GC线程数量 | 并行阶段活跃 | 并发+并行阶段活跃 |
额外内存消耗 | 约5% | 约10-15% |
特点:高吞吐量,对延迟不敏感
收集器 | 处理速度 | 资源消耗 | 总体评分 |
---|---|---|---|
Parallel GC | ★★★★★ | ★★★★☆ | 推荐 |
G1 GC | ★★★☆☆ | ★★★☆☆ | 可用 |
特点:对延迟敏感,需要快速响应
收集器 | 响应时间 | 用户体验 | 总体评分 |
---|---|---|---|
Parallel GC | ★★☆☆☆ | ★★☆☆☆ | 不推荐 |
G1 GC | ★★★★☆ | ★★★★☆ | 推荐 |
特点:大堆内存,长时间运行
收集器 | 可扩展性 | 长期稳定性 | 总体评分 |
---|---|---|---|
Parallel GC | ★★☆☆☆ | ★★★☆☆ | 不推荐 |
G1 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
参数 | 说明 | 建议值 |
---|---|---|
-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
系统特点:
Parallel GC表现:
G1 GC表现:
最终选择:G1 GC,牺牲约1.4%的吞吐量,换取更好的用户体验。
系统特点:
Parallel GC表现:
G1 GC表现:
最终选择:Parallel GC,提供更高的数据处理速度。
维度 | Parallel GC | G1 GC |
---|---|---|
设计目标 | 最大化吞吐量 | 可预测的低延迟 |
内存布局 | 连续分代 | 区域化分代 |
回收算法 | 全量标记-整理/复制 | 增量标记-复制 |
停顿特性 | 长而少 | 短而频繁 |
并发能力 | 无并发标记 | 并发标记 |
内存开销 | 低 | 中 |
CPU开销 | 低 | 中高 |
可预测性 | 低 | 高 |
可扩展性 | 中 | 高 |
选择Parallel GC的情况:
选择G1 GC的情况:
Java垃圾收集器技术仍在不断发展,新一代的ZGC和Shenandoah GC提供了更低的停顿时间,但目前G1 GC仍是大多数企业级应用的最佳选择。随着硬件性能的提升和应用对低延迟需求的增加,未来垃圾收集器将更加注重停顿时间的优化。
对于大多数现代Java应用,建议:
最终,选择合适的垃圾收集器应基于应用特性、业务需求和实际测试结果,而非仅仅依赖理论分析。
本文作者:大哥吕
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!