6.收集器G1和CMS的区别

CMS垃圾收集器以并发和低停顿时间为目标,采用标记清理算法,存在浮动垃圾和内存碎片问题。G1收集器则引入空间整合,避免大量碎片,通过分区和RememberedSet优化 MinorGC 效率,提供可预测的停顿时间模型,以用户定义的停顿时间为目标进行垃圾回收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CMS:以获取最短回收停顿时间为目标的收集器,基于并发“标记清理”实现
有人会好奇为什么标记清理算法会产生内存碎片!但是CMS仍采用这种算法呢?

答案是:因为CMS作为第一款实现用户线程和收集线程并发执行的收集器!当时的设计理念是减少停顿时间,最好是能并发执行!但是问题来了,如要用户线程也在执行,那么就不能轻易的改变堆中对象的内存地址!不然会导致用户线程无法定位引用对象,从而无法正常运行!而标记整理算法和复制算法都会移动存活的对象,这就与上面的策略不符!因此CMS采用的是标记清理算法!

              初始标记-->并发标记---->重新标记---->并发清理


过程:

1、初始标记:独占PUC,stop-the-world, 仅标记GCroots能直接关联的对象

2、并发标记:可以和用户线程并发执行,通过GCRoots Tracing 标记所有可达对象。

3、重新标记:独占CPU,stop-the-world, 对并发标记阶段用户线程运行产生的垃圾对象进行标记修正,以及更新自我拯救那部分逃逸对象

4、并发清理:可以和用户线程并发执行,清理垃圾

优点:
并发,低停顿

缺点:
1、对CPU非常敏感:在并发阶段虽然不会导致用户线程停顿,但是会因为占用了一部分线程使应用程序变慢

2、无法处理浮动垃圾:在最后一步并发清理过程中,用户线程执行也会产生垃圾,但是这部分垃圾是在标记之后,所以只有等到下一次gc的时候清理掉,这部分垃圾叫浮动垃圾。由于并发清理的时候,用户线程也在运行,就需要保证用户线程在运行的时候需要留有部分内存以供使用。但是当这部分内存不足以给用户线程正常使用时,就会出现一次 “Concurrent Mode Failure”,一旦出现了“Concurrent Mode Failure”,便会开启后备方案,临时使用SerialOld收集器进行收集工作。

3、CMS使用“标记-清理”法会产生大量的空间碎片,当碎片过多,将会给大对象空间的分配带来很大的麻烦,往往会出现老年代还有很大的空间但无法找到足够大的连续空间来分配当前对象,不得不提前触发一次FullGC,

为了解决这个问题CMS提供了一个开关参数,用于在CMS顶不住,要进行FullGC时开启内存碎片的合并整理过程,但是内存整理的过程是无法并发的,空间碎片没有了但是停顿时间变长了

CMS 出现FullGC的原因:
1、年轻代晋升到老年代没有足够的连续空间,很有可能是内存碎片导致的,因此会触发FULL GC

2、在并发过程中JVM觉得在并发过程结束之前堆就会满,需要提前触发FullGC

CMS失败后使用备案SerialOld收集器
G1:是一款面向服务端应用的垃圾收集器
         初始标记-->并发标记---->最终标记---->筛选回收
            G1只有并发标记阶段能做到用户线程和回收线程并发执行!!!!

G1可以不需要其它收集器配合就能独立管理整个GC堆
目标是替换掉CMS收集器


特点:
1、并行与并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。

2、分代收集:分代概念在G1中依然得以保留。虽然G1可以不需要其它收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。也就是说G1可以自己管理新生代和老年代了。

3、空间整合,没有内存碎片产生:由于G1使用了独立区域(Region)概念,G1从整体来看是基于“标记-整理”算法实现收集,从局部(两个Region)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片。

在最后筛选回收阶段,对每个region里的回收对象价值(回收该区域的时间消耗和能得到的内存比值)最后进行排序,用户可以自定义停顿时间,那么G1就可以对部分的region进行回收!这使得停顿时间是用户自己可以控制的!!!!

但是每个region之间是有互相引用的依赖关系的!这导致在MinorGC的时候会同时对老年代进行扫描(甚至是整个堆扫描),那就会导致MinorGC的效率低下,时间变长!

如何解决???
维护一个Remebered Set集合来存放各个Region之间的引用关系!当进行GC Roots Tracing 的时候就可以只扫描set里的关联region!而不用全堆扫描啦!!!

4、可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用这明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

可预测的停顿什么意思呢?
G1可以有计划的避免在整个JAV堆中进行垃圾收集,可以对每个region里的回收对象价值(回收该区域的时间消耗和能得到的内存比值)进行分析,在最后筛选回收阶段,对每个region里的回收对象价值(回收该区域的时间消耗和能得到的内存比值)最后进行排序,用户可以自定义停顿时间,那么G1就可以对部分的region进行回收!这使得停顿时间是用户自己可以控制的!!!!

与其它收集器相比,G1变化较大的是它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留了新生代和来年代的概念,但新生代和老年代不再是物理隔离的了它们都是一部分Region(不需要连续)的集合。同时,为了避免全堆扫描,G1使用了Remembered Set来管理相关的对象引用信息。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会有遗漏了。

最后筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划(可预测的停顿),这一过程同样是需要停顿线程的,但Sun公司透露这个阶段其实也可以做到并发,但考虑到停顿线程将大幅度提高收集效率,所以选择停顿。
————————————————
版权声明:本文为优快云博主「五山口老法师」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/Fly_as_tadpole/article/details/85047616

<think>好的,我现在需要详细描述CMS、G1ZGC这三个垃圾收集器。首先,我要确认每个收集器的基本信息,包括它们的工作方式、适用场景、优点缺点。然后比较它们之间的差异,可能还需要提到它们的演变背景,为什么会有新的收集器出现。 首先,CMS收集器,我记得是并发标记清除,主要目标是减少停顿时间,适用于对延迟敏感的应用。它分为几个阶段:初始标记、并发标记、重新标记、并发清除。不过CMS的问题可能在于内存碎片CPU资源敏感,还有在并发阶段可能产生浮动垃圾,导致Full GC。 接下来是G1收集器,它取代了CMS,采用了分Region的内存布局,可以预测停顿时间。G1的工作分为年轻代老年代的收集,使用Remembered Set来跟踪跨Region引用,避免全堆扫描。它的优势在于可控的停顿时间,适合大内存应用,但可能吞吐量稍低。 然后是ZGC,这是较新的收集器,专注于低延迟,甚至亚毫秒级的停顿。它使用了着色指针读屏障技术,实现并发处理大部分垃圾回收任务。ZGC适合非常大的堆内存,比如TB级别,而且停顿时间不会随堆大小增加而增加。不过可能需要更高的JDK版本支持,比如JDK11以上,并且还在不断优化中。 我需要组织这些信息,分点详细说明每个收集器,包括它们的原理、阶段、优缺点,以及适用场景。同时,用户可能想了解它们之间的对比,所以最后可以做一个对比表格,帮助理解差异。 需要注意的是,避免技术性错误,比如CMS在JDK9后被标记为废弃,而ZGC在后续版本中逐渐成熟。此外,G1是默认收集器,而ZGC可能在最新的JDK版本中成为默认选项,需要确认当前情况。可能还要提到参数设置,比如如何启用这些收集器,以及调优建议。 另外,要使用中文,保持结构清晰,可能分章节介绍每个收集器,最后总结对比。需要检查术语的准确性,比如并发并行的区别CMS是并发收集,而并行收集可能指多个GC线程同时工作。 最后,确保内容详细但不过于冗长,覆盖关键点即可。可能还需要举例子或者使用场景,帮助读者理解何时选择哪种收集器。</think>以下是JavaCMS、G1ZGC垃圾收集器的详细对比解析: --- ### **1. CMS收集器(Concurrent Mark-Sweep)** #### **核心机制** - **目标**:以**最小停顿时间**为核心,适用于对延迟敏感的应用(如Web服务)。 - **工作阶段**: 1. **初始标记(Initial Mark)**:Stop-The-World(STW),标记GC Roots直接关联的对象。 2. **并发标记(Concurrent Mark)**:用户线程并发,遍历整个对象图。 3. **重新标记(Remark)**:STW,修正并发标记期间变动的对象。 4. **并发清除(Concurrent Sweep)**:删除不可达对象。 - **内存布局**:传统分代模型(年轻代+老年代)。 #### **优点** - **低延迟**:大部分阶段应用线程并发执行。 - **适合场景**:老年代回收频繁且要求低停顿(如响应时间敏感的OLTP系统)。 #### **缺点** - **内存碎片**:标记-清除算法不整理内存,需定期Full GC(使用Serial Old收集器)。 - **浮动垃圾**:并发阶段用户线程可能产生新垃圾,需预留内存空间。 - **CPU敏感**:并发阶段占用CPU资源,可能影响吞吐量。 #### **关键参数** ```bash -XX:+UseConcMarkSweepGC # 启用CMS -XX:CMSInitiatingOccupancyFraction=70 # 老年代70%时触发CMS -XX:+UseCMSCompactAtFullCollection # Full GC时整理内存 ``` --- ### **2. G1收集器(Garbage-First)** #### **核心机制** - **目标**:平衡**吞吐量****可控停顿时间**,替代CMS成为JDK9+默认收集器。 - **内存模型**:将堆划分为**多个等大小Region**(1MB~32MB),动态归属为Eden/Survivor/Old/Humongous区。 - **工作流程**: 1. **年轻代收集**:STW,复制存活对象到Survivor或Old区。 2. **混合收集(Mixed GC)**:回收部分Old Region(基于垃圾比例优先级)。 3. **Full GC(Fallback)**:当回收速度跟不上分配速度时触发(类似Serial Old)。 #### **优点** - **可预测停顿**:通过`-XX:MaxGCPauseMillis`设置目标停顿时间(默认200ms)。 - **高效内存利用**:Region设计减少内存碎片,适合大堆(4GB+)。 - **并行并发**:充分利用多核CPU,部分阶段并发执行。 #### **缺点** - **内存开销**:维护跨Region引用的Remembered Set占用额外内存。 - **吞吐量略低**:相比Parallel Scavenge/Old,吞吐量降低约10%。 #### **关键参数** ```bash -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m # 设置Region大小 ``` --- ### **3. ZGC(Z Garbage Collector)** #### **核心机制** - **目标**:**亚毫秒级停顿**(<10ms),支持TB级堆内存(JDK15+正式生产可用)。 - **关键技术**: - **着色指针(Colored Pointers)**:利用指针元数据标记对象状态(无需对象头)。 - **读屏障(Load Barrier)**:动态处理并发阶段的对象访问。 - **并发压缩**:在用户线程运行时整理内存,消除碎片。 - **阶段**: 1. **并发标记**:遍历对象图并标记存活对象。 2. **并发预备重分配**:确定需压缩的Region。 3. **并发重分配**:移动对象并更新引用。 4. **并发重映射**:修正旧地址的访问。 #### **优点** - **极致低延迟**:停顿时间几乎不随堆大小增长。 - **全堆操作**:无分代假设,简化回收逻辑。 - **高吞吐量**:并发处理能力接近G1。 #### **缺点** - **内存开销**:需额外内存维护元数据(约15%~20%堆容量)。 - **JDK版本依赖**:需JDK11+(生产推荐JDK17+)。 #### **关键参数** ```bash -XX:+UseZGC -XX:ZAllocationSpikeTolerance=5 # 容忍内存分配速率波动 -XX:ZProactive # 启用主动回收(默认开启) ``` --- ### **4. 三大收集器对比** | **特性** | **CMS** | **G1** | **ZGC** | |---------------------|----------------------------------|------------------------------------|-----------------------------------| | **目标** | 最小停顿时间 | 平衡吞吐量可控停顿 | 亚毫秒级停顿,超大堆 | | **算法** | 标记-清除(不整理) | 标记-整理(分Region) | 着色指针+并发压缩 | | **最大堆** | 4-6GB(受碎片限制) | 百GB级 | TB级 | | **停顿时间** | 10ms-100ms | 10ms-200ms(可配置) | <1ms-10ms | | **内存开销** | 低 | 中(Remembered Set) | 高(元数据) | | **并发/并行** | 并发标记/清除 | 并行年轻代收集,并发老年代标记 | 全阶段并发 | | **适用场景** | 低延迟中小堆应用 | 大堆、需平衡吞吐延迟 | 超大堆、极致低延迟(金融、实时) | | **JDK支持** | JDK8默认,JDK9+废弃 | JDK9+默认 | JDK11+实验,JDK15+生产 | --- ### **5. 选择建议** 1. **CMS**:已逐渐淘汰,仅在JDK8及以下版本的老系统中使用。 2. **G1**:JDK8+通用选择,适合堆内存4GB~50GB,要求平衡吞吐延迟。 3. **ZGC**:JDK15+首选,适用于堆内存50GB+、要求极低延迟(如高频交易系统)。 --- ### **6. 性能调优要点** - **CMS**:监控Full GC频率,调整`CMSInitiatingOccupancyFraction`避免并发失败。 - **G1**:优化`MaxGCPauseMillis`,避免Region过大导致Humongous对象分配。 - **ZGC**:确保物理内存充足,预留额外内存(堆大小的20%)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值