CMS与G1 三色标记算法

承上启下

jdk8默认回收器ps+po,jdk9默认就是G1了。但是CMS是并行回收的开始

CMS

在这里插入图片描述

CMS :ConcurrentMarkSweep 老年代 并发的,垃圾回收和应用程序同时运行,降低STW的时间(200MS)
CMS有一些问题,所以没有任何版本默认是CMS的,只能手工指定。CMS是MarkSweep,必然会导致碎片,当碎片到一定程度,CMS老年代分配对象分配不下时,使用serialold进行老年代串行回收。
会产生浮动垃圾
解决方案:降低触发CMS的阈值,保持老年代有足够的空间
-XX:CMSInitiatingOccupancyFraction 92% 降低百分比

六个阶段
预处理阶段
初始标记:STW,标记出根对象。因为只标记跟对象,所以很快
并发标记:标记垃圾,浪费80%GC时间,同应用程序一同运行
重新标记:STW,并发处理中产生了新的垃圾,或者有一些垃圾重新被使用,不再是垃圾。因为大部分垃圾在并发标记时处理过了,所以也很快。
并发清理:将产生的垃圾清除掉,但是同时也会产生新的垃圾。也就是浮动垃圾,这种浮动垃圾只能等待下一个垃圾回收进行处理
整理阶段

三色标记,并发标记时的算法

CMS使用的是三色标记+Incremental Update算法
G1使用的是三色标记+snapshot at the begining (SATB)算法
ZGC: Colored Pointers+写屏障
Shenandoah :Colored Pointers+读屏障

在这里插入图片描述

黑色:自身和成员变量均已标记完成
灰色:自身被标记完成,成员变量未被标记
白色:未被标记的对象(垃圾)

漏标情况,会将本来不是垃圾得对象,当作垃圾回收了
在运行态中,1、黑色对象指向了白色对象,2、并且同时,灰色对象取消了白色对象的引用。
就会产生白色对象漏标的情况。
因为黑色对象已经标记完毕,不会再去扫描,并且也没有灰色对象的指向,所以漏标了

漏标的应对,打破这两种条件之一即可

Incremental update 增量更新,关注引用的增加,如果发现黑色指向了白色,把黑色重新标记为白色,remark过程将重新扫描属性。但是会造成重复扫描已扫描过的属性。(CMS对漏标的处理方式)

SATB snapshot at the begining 关注引用的删除,当灰色对象对白色对象的引用删除后,将这个引用推到GC的堆栈中,保证白色对象还是能够被扫描到(G1对漏标的处理方式)
在扫描时拿到这个引用,由于有Rset存在,不需要扫描整个堆去查找指向白色的引用,效率比较高。
SATB配合Rset,使得整个效率提高

G1

不再进行物理分代,而是逻辑分代。Garbage First 垃圾优先 的垃圾回收器

官方入门:https://www.oracle.com/technical-resources/articles/java/g1gc.html

The Garbage First Garbage Collector (G1 GC) is the low-pause, server-style generational garbage collector for Java HotSpot VM. The G1 GC uses concurrent and parallel phases to achieve its target pause time and to maintain good throughput. When G1 GC determines that a garbage collection is necessary, it collects the regions with the least live data first (garbage first).

G1是一种服务端应用使用的垃圾收集器,目标使用在多核,大内存的机器上,它在大多数情况下可以实现指定的GC暂停时间,同时还能保持较高的吞吐量
G1的吞吐量比PS+PO降低了10%-15%,但是STW时间控制在200ms左右。需要响应时间优先,使用G1

G1的特点

并发收集(同CMS差不多,三色标记算法。后续的ZGC,shenadoah使用 colored pointer颜色指针算法,颜色指针会拿出3bit来记录引用变化。。)
压缩空闲空间不会延长GC的暂停时间
更易预测的GC暂停时间
适用不需要实现很高吞吐量的场景

G1区域的内存划分

在这里插入图片描述

逻辑分区Region:Eden区、Survivor区、Old区、Hunmongous区(大对象区,超过单个region的50%就是Hunmongous,并且可以占用连续的多个内存)

G1的内存区域不是固定的eden区或者old区。比如本来是eden区,在垃圾回收之后,可能就会用作old区来使用

G1基本概念

Cset = collection set

一组可被回收的分区的集合
在Cset中存活的数据会在GC过程中被移动到另一个可用分区
Cset的分区可以来自Eden空间,Survivor空间、或者Old空间
Cset占用不到整个堆空间1%大小

cset 收集到了所有非dirty card,当需要垃圾回收时,直接区cset中取

Rset = Remember set

记录了其他Region中的对象到本Region的引用

这样使得垃圾回收器不需要扫描整个堆,来找到谁引用了当前分区中的对象,只需要扫描Rset即可
但是在每次给对象赋引用时,都需要在Rset做一些额外得记录(做的额外的这些记录,在GC中称为写屏障。注意和jvm中的内存屏障不是一个概念!)

每个Region都要有一块区域记录Rset,浪费10%左右空间,ZGC中没有Rset

G1新生代老年代的分配

分代时,新生代和老年代1:2,尽量不要改
G1新老年代比例,5%-60%,尽量不要手工指定。也不要手工指定,因为这是G1预测停顿时间的基准,G1动态调整STW时间,如果发现超过200ms,降低回收比例。

G1 GC何时触发

触发顺序
1、YongGC,会复制存活对象到其他区域
2、达到mixedGC阈值,进行mixedGC,这个时候年轻代,年老代哪个满了,回收哪个
3、Old空间被占满,FullGC开始,使用serial old垃圾回收器,所以尽量不要FullGC

YoungGC:Eden空间不足,多线程并行执行,并且会动态伸缩Eden区大小,把控STW时间

FullGC:Old空间不足,使用Serial old垃圾回收器,所以尽量不要产生FullGC!G1并不是不会触发FGC,如果对象飞快占据空间,仍然会产生FullGC
如果G1产生FullGC(尽量避免FullGC),jdk10之前fullGC都是串行,之后是并行。
处理
1、扩大内存
2、提高CPU性能(回收的快,业务逻辑产生对象的速度固定,垃圾回收快,内存空间越大)
3、降低MixedGC触发的阈值,让MixedGC提早发生(默认是45%)

MixedGC,G1的正常回收过程,相当于CMS
-XX:InitiatingHeapOccupancyPercent 默认值45%,当O超过这个值时,启动mixedGC
1、初始标记
在这里插入图片描述
2、并发标记
在这里插入图片描述
3、最终标记
将改变的变量,再次标记一次在这里插入图片描述
4、并行筛选标记
将最需要回收的对象进行回收,并且在回收时直接将region指向另一块空间,同时进行了压缩,不会像CMS出现太多的碎片在这里插入图片描述

行业的前沿

阿里的多租户JVM
分为不同的JVM区,合并位一个整体的JVM,每租户单个空间。
session based GC,适用于web application的GC,session消失直接回收。
总的来说仍是分而治之的思想

<think>好的,我现在需要回答用户关于G1垃圾回收器中三色标记法的实现原理的问题。首先,我要回顾一下已有的知识,并查看提供的参考资料。 根据引用[1],G1是基于标记-整理算法,但局部使用复制算法,并且采用了Region的内存布局。引用[2]提到CMS和G1在并发回收时使用三色标记法,但存在多标和漏标的问题。引用[3]指出垃圾回收算法的基础,而引用[4]说明主流的收集器使用可达性分析,三色标记法用颜色标记对象状态。 首先,我需要解释三色标记法的基本概念。三色标记法将对象分为白、灰、黑三种颜色,分别表示未扫描、正在扫描和已扫描。在G1中,这个过程是并发进行的,所以需要处理并发时的多标和漏标问题。 接下来,要结合G1的特点。G1将堆分成多个Region,这可能影响标记的过程。并发标记阶段如何用户线程同时运行,这时候如何确保标记的正确性?这里可能会提到SATB(Snapshot-At-The-Beginning)算法,用于处理漏标问题,如引用[2]中提到的。 然后,需要说明G1如何解决漏标和多标。漏标通常通过写屏障和SATB来处理,确保在并发阶段开始时的对象关系快照。多标则可能导致浮动垃圾,但可以通过下一次回收处理。 另外,引用[1]提到G1是局部收集,基于Region的设计,这可能意味着标记过程需要针对不同Region进行优化,可能涉及记忆集(Remembered Set)来记录跨Region引用,但这可能三色标记法本身关联不大,但需要确认。 需要确保术语正确,比如白色是不可达,黑色是处理完的,灰色是待处理的。同时,强调并发阶段的问题及解决方案。 最后,总结G1如何结合三色标记法实现高效的并发回收,并处理标记过程中的问题。同时,可能需要生成相关问题,但用户已要求,所以放在最后。 现在需要组织这些思路,确保逻辑清晰,引用正确的资料,并符合格式要求,如使用中文,数学表达式用$...$,独立公式用$$...$$,但这里可能用不到数学公式,但需要检查是否有需要的地方。例如,解释标记过程可能用流程图或公式,但用户问题可能不需要。 需要避免技术错误,比如确认SATB确实是G1使用的,而CMS可能用增量更新。同时,确保解释清楚写屏障的作用。 最后,检查是否符合所有系统级指令,特别是引用标注的正确位置。</think>### G1垃圾回收器中三色标记法的实现原理 G1(Garbage First)垃圾回收器采用**三色标记法**作为并发标记阶段的核心算法,用于高效识别堆内存中的存活对象。其实现原理可分为以下关键点: --- #### 1. **三色标记法的基本定义** 三色标记法通过颜色标记对象状态,基于可达性分析算法: - **白色**:未被垃圾回收器访问,可能为垃圾对象[^4]。 - **灰色**:对象被访问,但其引用的子对象还未被完全扫描。 - **黑色**:对象及其子对象均被扫描完成,确定为存活对象。 标记过程本质上是**从GC Roots出发**,逐步遍历对象图的广度优先搜索(BFS)过程。 --- #### 2. **G1的并发标记挑战** G1的标记阶段需要用户线程并发执行,这会引发两种问题: - **多标(浮动垃圾)**:标记过程中,用户线程可能切断某些对象的引用,但这些对象已被标记为存活(黑色)。这类垃圾需等待下次回收处理[^2]。 - **漏标(对象消失)**:用户线程修改引用关系,导致存活对象被误标为白色。例如: - 赋值器插入一条从黑色对象到白色对象的引用。 - 赋值器删除所有从灰色对象到该白色对象的引用。 --- #### 3. **G1解决漏标的机制:SATB写屏障** G1采用**SATB(Snapshot-At-The-Beginning)算法**解决漏标问题: - **原理**:在并发标记开始时,对对象引用关系建立快照。即使并发过程中引用关系被修改,快照中的存活对象仍会被标记。 - **实现**:通过**写屏障(Write Barrier)**技术,拦截对象引用修改操作: ```java // 伪代码示例:SATB写屏障 void pre_write_barrier(Field field, Object new_value) { if (current_color(field) == BLACK && new_value == WHITE) { add_to_satb_queue(field); // 记录原引用关系 } } ``` 所有被删除的引用会被记录到SATB队列,后续重新扫描这些引用,确保存活对象不被遗漏。 --- #### 4. **G1的分区(Region)标记优化** G1将堆划分为多个大小相等的Region,标记时针对不同Region采用差异化策略: - **并发标记阶段**:遍历所有Region,但仅标记存活对象。 - **局部回收(Mixed GC)**:根据Region的存活对象比例(垃圾“密度”)优先回收高收益Region[^1]。 --- #### 5. **标记过程的阶段划分** G1的标记过程分为多个阶段以降低停顿时间: 1. **初始标记(Initial Mark)**:暂停用户线程(STW),标记从GC Roots直接可达的对象。 2. **并发标记(Concurrent Mark)**:用户线程并发遍历对象图。 3. **最终标记(Final Mark)**:处理SATB队列中的剩余引用,修正漏标对象。 4. **清理阶段(Cleanup)**:统计Region存活数据,为Mixed GC做准备。 --- ### 总结 G1通过**三色标记法+SATB写屏障**的组合,在并发标记阶段高效识别存活对象,同时解决漏标问题。其面向局部收集的设计Region内存布局进一步优化了标记效率,降低了停顿时间[^4]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值