01_2_JVM_垃圾收集器

以下是十大主流 Java 垃圾收集器(GC)的详细解析,包括特性、区别和缺点。这些收集器随着 JDK 版本的迭代逐步演进,适应不同场景的需求。

  1. Serial 收集器
    特性
    单线程:GC 线程与用户线程串行执行(Stop-The-World)。
    新生代采用复制算法,老年代(Serial Old)采用标记-压缩算法。
    简单高效,无线程交互开销,适用于客户端模式或小内存应用(如嵌入式)。
    缺点
    单线程导致长时间停顿(Full GC 时尤为明显)。
    适用场景
    JDK 1.3 前默认,适合单核 CPU 或测试环境。

  1. ParNew 收集器
    特性
    Serial 的多线程版本,新生代并行 GC(多线程复制算法)。
    需搭配 CMS 使用(CMS 默认的新生代收集器)。
    缺点
    依赖单线程的老年代 Serial Old,Full GC 时效率低。
    适用场景
    多核服务器中与 CMS 配合使用(JDK 7 及之前)。

  1. Parallel Scavenge(吞吐量优先收集器)
    特性
    新生代并行收集,老年代(Parallel Old)采用多线程标记-压缩算法。
    关注吞吐量(用户代码运行时间 / 总时间),而非低延迟。
    支持自适应调节策略(自动调整堆大小、晋升阈值等)。
    缺点
    无法与 CMS 搭配使用。
    适用场景
    JDK 8 默认收集器,适合后台计算型任务(如批处理)。

  1. CMS(Concurrent Mark-Sweep)
    特性
    老年代并发低延迟收集器,标记-清除算法。
    阶段:初始标记(STW)→ 并发标记 → 重新标记(STW)→ 并发清除。
    减少停顿时间,GC 线程与用户线程并发执行。
    缺点
    内存碎片:标记-清除算法导致 Full GC 前需压缩。
    CPU 敏感:并发阶段占用线程资源,降低吞吐量。
    浮动垃圾:并发清理时用户线程可能产生新垃圾。
    适用场景
    JDK 9 前老年代主流选择,已逐渐被 G1 取代。

  1. G1(Garbage-First)
    特性
    面向服务端,JDK 9+ 默认收集器,支持 Region 分区模型。
    混合回收:新生代(复制算法)+ 老年代(标记-压缩算法)。
    可预测停顿:通过划分优先级区域(Garbage-First)控制回收时间。
    支持并发标记与增量压缩。
    缺点
    内存占用高(记录跨 Region 引用)。
    小内存场景表现不如 CMS。
    适用场景
    大内存(4GB+)、低延迟需求(如微服务)。

  1. ZGC(Z Garbage Collector)
    特性
    亚毫秒级停顿(JDK 15 后正式发布)。
    全并发的标记-整理算法,基于 指针染色(Colored Pointers)。
    支持 TB 级堆内存,停顿时间与堆大小无关。
    缺点
    高 CPU 和内存开销(需 64 位系统)。
    JDK 11+ 实验性支持,JDK 15+ 生产可用。
    适用场景
    超大堆(如大数据、实时系统)。

  1. Shenandoah
    特性
    低延迟,与 ZGC 竞争,由 Red Hat 开发。
    并发压缩(Brooks 指针技术),减少内存碎片。
    停顿时间与堆大小无关。
    缺点
    不在 Oracle JDK 中,需使用 OpenJDK。
    早期版本稳定性不足。
    适用场景
    类似 ZGC,适用于需要低延迟的 OpenJDK 环境。

  1. Epsilon
    特性
    无操作的 GC,只分配内存,不回收(JDK 11+)。
    极低开销,无 GC 相关停顿。
    缺点
    内存耗尽时直接 OOM。
    适用场景
    性能测试、短生命周期任务(如 Serverless)。

  1. Serial Old
    特性
    Serial 收集器的老年代版本,单线程标记-压缩算法。
    缺点
    仅用于客户端模式或 CMS 后备方案。

  1. Parallel Old
    特性
    Parallel Scavenge 的老年代版本,多线程标记-压缩算法。
    缺点
    延迟较高,适用于吞吐量优先场景。

对比总结
收集器线程模式算法适用场景缺点Serial单线程复制/标记-压缩客户端、小内存长时间停顿ParNew多线程复制配合 CMS 的多核服务器依赖 Serial OldParallel多线程复制/标记-压缩高吞吐量任务高延迟CMS并发标记-清除低延迟老年代回收内存碎片、CPU 敏感G1并发/并行分区复制+压缩大内存、平衡吞吐与延迟内存占用高ZGC全并发指针染色+压缩超大堆、亚毫秒延迟高资源消耗Shenandoah全并发Brooks 指针+压缩OpenJDK 低延迟环境非 Oracle JDK 官方支持Epsilon无操作-测试、短生命周期任务不回收内存

选择建议
小内存/客户端:Serial。
高吞吐量:Parallel Scavenge + Parallel Old。
低延迟(JDK 8):ParNew + CMS。
大内存平衡型:G1(JDK 8+)。
超大堆极致低延迟:ZGC(JDK 15+)或 Shenandoah(OpenJDK)。
特殊场景:Epsilon(性能测试)。
随着 JDK 版本升级,G1、ZGC、Shenandoah 是未来主流,CMS 和 Parallel 逐渐被淘汰。

以下是 ParNew + CMS 这一垃圾收集器组合的详细解析,涵盖其工作机制、适用场景、优缺点及配置调优建议。
ParNew + CMS 组合概述
角色分工
ParNew:负责新生代的垃圾回收(并行、多线程)。
CMS(Concurrent Mark-Sweep):负责老年代的垃圾回收(并发、低延迟)。
目标
通过 新生代并行回收 + 老年代并发回收,减少垃圾回收的停顿时间(STW),适合对延迟敏感的应用(如 Web 服务)。

工作机制

  1. 新生代回收(ParNew)
    算法:多线程复制算法(Stop-The-World)。
    触发条件
    新生代 Eden 区满时触发 Minor GC。
    存活对象被复制到 Survivor 区(或直接晋升到老年代)。
    特点
    多线程并行回收,充分利用多核 CPU。
    与 Serial 收集器行为类似,但线程数可控。
  2. 老年代回收(CMS)
    CMS 分为 4 个阶段,目标是尽量减少 STW 时间:
    初始标记(Initial Mark)
    STW:标记 GC Roots 直接关联的老年代对象。
    触发条件:老年代空间使用率超过阈值(默认 -XX:CMSInitiatingOccupancyFraction=68%)。
    并发标记(Concurrent Mark)
    并发:从 GC Roots 遍历整个对象图,标记存活对象。
    用户线程与 GC 线程并发执行,无需暂停应用。
    重新标记(Remark)
    STW:修正并发标记期间因用户线程运行导致的标记变动(增量更新或 SATB)。
    多线程加速,停顿时间通常较短。
    并发清除(Concurrent Sweep)
    并发:清除未被标记的垃圾对象(标记-清除算法)。
    用户线程继续运行,可能产生“浮动垃圾”(需下次 GC 清理)。

核心配置参数
参数作用-XX:+UseParNewGC启用 ParNew 作为新生代收集器。-XX:+UseConcMarkSweepGC启用 CMS 作为老年代收集器。-XX:ParallelGCThreads=N设置 ParNew 和 CMS 的并行线程数(默认与 CPU 核数相关)。-XX:CMSInitiatingOccupancyFraction=N设置老年代空间使用率阈值,触发 CMS 回收(默认 68%)。-XX:+UseCMSCompactAtFullCollectionFull GC 时压缩老年代(减少碎片,但增加停顿时间)。-XX:CMSFullGCsBeforeCompaction=N执行 N 次 Full GC 后触发一次压缩(默认 0,每次 Full GC 都压缩)。

优点
低延迟
CMS 的并发标记和清除阶段与用户线程并行,大幅减少 STW 时间(尤其是老年代回收)。
新生代高效
ParNew 多线程回收新生代,适合多核服务器环境。
适用性广泛
JDK 7 及之前版本的推荐组合,适合响应时间敏感的应用(如在线服务)。

缺点与挑战
内存碎片
CMS 使用标记-清除算法,老年代会产生内存碎片,可能触发 Full GC(采用 Serial Old 单线程压缩,导致长时间停顿)。
解决方案:配置
-XX:+UseCMSCompactAtFullCollection 和
-XX:CMSFullGCsBeforeCompaction。
CPU 资源竞争
并发标记和清除阶段占用 CPU 资源,可能降低应用吞吐量。
建议:预留足够 CPU 资源(如核数 > 4)。
浮动垃圾(Floating Garbage)
并发清理期间用户线程可能产生新垃圾,需预留空间(默认老年代阈值 68%)。
风险:若预留空间不足,触发“并发模式失败”(Concurrent Mode Failure),退化为 Serial Old 单线程 Full GC。
配置复杂
需手动调整阈值、线程数等参数,否则易引发性能问题。

调优建议
避免并发模式失败

增大老年代空间(-Xmx)或降低触发阈值(-XX:CMSInitiatingOccupancyFraction)。
控制碎片化
定期 Full GC 压缩老年代(通过 CMSFullGCsBeforeCompaction)。
监控与诊断
使用 -XX:+PrintGCDetails 和工具(如 GC Log Analyzer)分析 GC 日志,观察并发模式失败频率。
线程数优化
根据 CPU 核数设置
-XX:ParallelGCThreads(默认与核数相同,超线程需谨慎)。

适用场景
低延迟需求:如 Web 服务、实时数据处理。
中大型堆内存(4GB~16GB),且 CPU 核数充足(≥4)。
JDK 7 或早期版本,尚未迁移到 G1/ZGC 的应用。

淘汰与替代
JDK 9+:CMS 被标记为废弃(Deprecated),JDK 14 中移除。
替代方案:
G1:JDK 8+ 默认,平衡吞吐与延迟。
ZGC/Shenandoah:超低延迟、超大堆场景(JDK 11+)。

总结
ParNew + CMS 是经典的低延迟 GC 组合,适合老版本 JDK 和多核服务器环境,但需谨慎调优以避免碎片和并发失败。随着 JDK 版本升级,G1 和 ZGC 是更现代的替代方案。

以下是关于 G1(Garbage-First)垃圾收集器的详细解析,涵盖其设计思想、核心机制、工作流程、优缺点及调优建议,帮助深入理解这一现代垃圾收集器。

  1. G1 概述
    定位
    JDK 7 引入(JDK 9+ 成为默认),面向服务端应用的 低延迟、高吞吐 收集器,适合大内存(数 GB 到数十 GB)场景。
    核心目标
    可预测的停顿时间模型(Soft Real-Time):通过划分 Region 和优先级回收,控制每次 GC 的停顿时间(如设置
    -XX:MaxGCPauseMillis=200ms)。
    平衡吞吐与延迟:兼具并行与并发回收能力。

  1. 核心设计思想
    2.1 Region 分区模型
    堆内存划分:将堆划分为多个大小相等(默认约 2MB~32MB,可调)的 Region,每个 Region 可动态扮演以下角色:
    Eden / Survivor / Old / Humongous(存放大对象,跨多个 Region)。
    优势:
    避免传统分代模型的内存连续分配问题。
    按 Region 回收,优先处理垃圾比例高的 Region(Garbage-First 命名由来)。
    2.2 分代收集的演进
    逻辑分代:仍保留新生代(Young)和老年代(Old)概念,但物理上不连续。
    动态调整:Region 的角色随回收动态变化,无需固定比例。

  1. G1 的工作流程
    3.1 新生代回收(Young GC)
    触发条件:Eden 区占满时触发。
    过程(STW 并行):
    根扫描:标记 GC Roots 直接引用的对象。
    复制存活对象:将 Eden 和 Survivor 区的存活对象复制到新的 Survivor 区(或晋升到 Old 区)。
    更新引用:调整对象引用指针。
    特点:多线程并行,停顿时间较短。
    3.2 老年代回收(Mixed GC)
    触发条件:老年代占用超过阈值(
    -XX:InitiatingHeapOccupancyPercent=45%)。
    阶段:
    初始标记(Initial Mark)(STW):标记 GC Roots 直接关联的对象(与 Young GC 同步执行)。
    并发标记(Concurrent Mark):遍历对象图,标记存活对象(与用户线程并发)。
    最终标记(Remark)(STW):处理 SATB(Snapshot-At-The-Beginning)记录的变化,修正标记。
    筛选回收(Evacuation)(STW):
    计算各 Region 的回收价值(垃圾比例、回收时间)。
    选择收益最高的 Region 进行回收(复制算法,存活对象移动到空闲 Region)。

  1. 核心特性
    4.1 并发与并行结合
    并发阶段:标记阶段与用户线程并发执行(减少停顿)。
    并行阶段:Young GC 和 Mixed GC 的复制阶段多线程并行(提升吞吐)。
    4.2 SATB 算法
    Snapshot-At-The-Beginning:
    并发标记开始时对对象图快照,确保标记一致性。
    通过 Pre-Write Barrier 记录并发期间引用变化(写入前记录旧值)。
    4.3 增量压缩
    避免全堆压缩:通过每次 Mixed GC 部分 Region 的复制,逐步整理内存(减少 Full GC 触发)。

  1. 关键参数配置
    参数作用-XX:+UseG1GC启用 G1 收集器。-XX:MaxGCPauseMillis=200目标最大停顿时间(毫秒),G1 会尽量满足(但不保证)。-XX:InitiatingHeapOccupancyPercent=45触发并发标记的老年代占用阈值(百分比)。-XX:G1HeapRegionSize=N设置 Region 大小(1MB~32MB,需为 2 的幂)。-XX:G1NewSizePercent / -XX:G1MaxNewSizePercent新生代占比范围(默认 5%~60%)。-XX:G1ReservePercent=10保留空间(避免晋升失败)。

  1. 优缺点分析
    优点
    低延迟:通过并发标记和增量回收,减少 STW 时间。
    大内存友好:分区模型适合堆内存从几 GB 到数十 GB。
    内存整理:逐步压缩,避免 CMS 的碎片问题。
    缺点
    内存占用:
    每个 Region 需维护记忆集(Remembered Set)和卡表(Card Table),占用额外空间(约堆的 10%~20%)。
    CPU 开销:
    并发标记和写屏障(Write Barrier)增加 CPU 负载。
    Full GC 回退:
    若并发回收速度跟不上对象分配速度,触发 Serial Old 单线程 Full GC(长时间停顿)。

  1. 调优建议
    避免 Full GC:
    确保堆大小足够(-Xms 和 -Xmx 一致,避免动态扩容)。
    监控晋升失败(Promotion Failure)和并发模式失败。
    停顿时间平衡:
    MaxGCPauseMillis 不宜过小(如 <50ms),否则导致频繁 GC。
    Region 大小调整:
    大对象多的应用可增大 G1HeapRegionSize(避免 Humongous 分配开销)。
    监控工具:
    使用 -Xlog:gc* 输出详细日志,结合工具(如 GCViewer、GCEasy)分析。

  1. 适用场景
    推荐场景:
    堆内存 ≥6GB,且要求低延迟(如微服务、实时交易系统)。
    JDK 8+ 的默认选择(替代 ParNew + CMS)。
    不适用场景:
    极小堆(<2GB)或对吞吐量极度敏感的场景(Parallel 更优)。

  1. 与 CMS 的对比
    特性G1CMS算法标记-复制 + 分区标记-清除内存模型Region 分区(无物理分代)传统连续分代碎片处理增量压缩需 Full GC 压缩停顿目标可预测停顿(软实时)尽量减少老年代停顿适用堆大小数 GB ~ 数十 GB一般 <4GBFull GC 触发较少(设计上避免)常见(并发模式失败或碎片)

  1. 总结
    G1 通过 Region 分区、并发标记 和 增量回收 实现了吞吐与延迟的平衡,是大内存应用的理想选择。尽管存在内存和 CPU 开销,但其可预测的停顿和自动调优能力使其成为现代 Java 应用的默认 GC。对于超大规模堆(如 TB 级),可考虑 ZGC 或 Shenandoah。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值