(9)G1算法,及CMS比较

Java 8 默认GC是Parallel GC。设计初衷避免Full GC

一、Garbage First(G1)

适用服务器端、大内存、多CPU情景。

高效率回收(high thoughput)同时,提供软实时中断(所以不是最快,Parallel gc最快)用户可指定时间上限,超过打断回收,恢复程序执行。 

二、收集算法:标记-清理 ,拷贝-复制

https://www.jianshu.com/p/e37789a2916c另一版本

2.1适用G1案例:

需要大内存(堆6GB以上)、 GC延迟(暂停时间0.5秒以内)

1、从CMS或者ParallelOld收集器切换到G1场景:

    活动对象占50%以上Java堆空间

    对象分配率或者提升率波动明显。

    没有长时间垃圾收集暂停

2、G1特性:像CMS一样, 能与应用程序线程并行;整理空闲空间更快、预测gc停顿时间;不牺牲大量吞吐性能、不需更大Java Heap

3、G1目标是取代CMS,CMS相比,更出色:

1)G1有整理内存过程,不产生很多碎片。2)STW可控,添加预测机制,可指定https://mp.weixin.qq.com/s/4ufdCXCwO56WAJnzng_-ow

2.2 region:

heap分成若干大小相等region,每个有一块连续虚拟内存,都关联Remembered set (RS)。

1、RS数据结构:hash table,数据是card table (heap中每512byte映射在card table 1byte)。RS里面存在region中live objects指针。

2、region数据变化:首先反映到card table中的一个或多个card上,RS通过扫描内部的card table得知region中内存使用情况和存活对象

3、大对象H-objs(大于等于region一半)

    1)直接分配到old gen,防止了反复拷贝移动。

    2)在global concurrent marking阶段的cleanup 和 full GC阶段回收。

    3)分配前检查是否超过 initiating heap occupancy percent和the marking threshold, 如超过启动global concurrent marking,提早回收,防止evacuation failures(疏散失败)和full GC。

    4)减少连续H-objs分配对GC影响,把大对象变为普通的对象,建议增大Region size

4、Region大小可设定:-XX:G1HeapRegionSize,从1M到32M,且是2的指数。不设定,根据Heap大小自动决定。

2.3 关于内存分配:

G1主要关注于多CPU多线程内存分配用 thread-local allocation buffers (TLABs)。线程都有自己buffers分配对象,buffers不够,重新申请一块内存自己thread-local里。对象内存分配被最小化私有buffers里缓解并发分配内存压力

region满,分配内存线程会选择新region。空region在一个linked list里,快速找新

大对象(大小超过region的3/4)分配TLABs外。分配到特殊区域(只包含大对象)

2.4执行过程: 

初始:STW(Stop the World ),所有mutator threads被停止,标记从GC Root开始直接可达对象,重启

并发:标记与应用程序线程并行耗时长

最终:标记上一阶段变化对象。需停顿,也要STW,并行很快完成。

筛选:对每区回收成本价值排序,根据指定停顿时间,选择性收集,统计每区对象数。

三、G1与CMS不同:

1. 分代收集

CMS:只回收老年代(配合年轻代收集器);堆分PermGen,YoungGen(分了两个survivo),OldGen

G1中:回收老、年轻代,Fully young gc(先回收年轻代垃圾)和Mixed gc(年轻代和老年代,部分回收); 平均分,每个区也保留了新老代,为单位收集

2. 如何处理跨代引用

老引用年轻影响young gc,需跨代处理。

避免收年轻代时扫描老年代,记录老年轻代引用,young gc时只要扫描这个记录。

CMS(基本用法):JVM将内存分成固定大小card,专门数据结构Card Table维护每个Card状态,一个字节对应一个Card(像内存page概念,page是硬件上,Card Table是软件上)。Card对象引用,对应Card Table上状态置为dirty,young gc扫描状态dirty的Card

G1:Card Table基础上引入remembered set(RSet)。每个region维护一个RSet,记录着引用Card(其他region)。A对象在regionA,B在regionB,且B.f = A,regionA的RSet中记录B的Card地址。可对region单独回收,RSet维护老到轻、老引用,只扫描region的RSet的Card

年轻(对象引用变化大)到老年代引用不需单独处理性能提升很大,如都记成本高。只需在老年代维护Card Table

3. 处理并发过程对象变化(未完成)

程序跟gc线程运行,新,旧的对象,引用关系变化。(每行表示一个内存状态,每列表示一个Card,4个):

    a)并发标记a:中状态,标记a b c e四个对象,0 1两个Card已经标好

    b)并发标记同时引用变:g不指d,b不再指c,指向d,这时处理Card 2,标记到g,标记结束,导致d对象丢失

(1)CMS初始标记:标记所有从root直接可达对象

     并发标记:1)从这些对象进一步搜索其他可达对象,构成存活对象图

    2)Card Table记录引用变化。但young gc时如dirty card没包含年轻代引用,card会重新标记为clean,可能将并发标记产生dirty card错误清除。

    3)因此CMS引入mod union table,一个bit对应一个Card,young gc在将Card Table设置为clean的时候会将对应的mod union table置为dirty。最终标记的时候会将Card Table或者mod union table是dirty的Card也作为root去扫描,从而解决并发标记过程产生的引用变化。CMS还需要处理并发过程从年轻代晋升到老年代的对象,处理方式是将这部分对象也作为root去扫描。

(2)G1用snapshot at the beginning(SATB)算法

GC开始时活对象快照。通过Root Tracing得到,根据三色标记算法,维持并发GC正确性

      初始标记时得到一个从root直接可达的snapshot,snapshot不可达对象都可gc,1)并发产生对象都默认活,留下一次处理2)对引用变化,将对应Card放SATB队列里最终标记时处理(如超阈值,并发标记也处理一部分,以队列中Card作为root进行扫描)

4. Write Barrier

时插入一条特定操作

CMS:老引用年轻,通过触发Write Barrier更新Card Table标志位。同步操作,更新引用时顺带执行,引入的消耗不大(两个指令)。

G1复杂:两个地方用Write Barrier:

    1.更新RSet的rememberd set Write Barrier:发生引用更新后,称Post Write Barrier

    2. 记录引用变化Concurrent Marking Write Barrier:发生引用变化前,称Pre Write Barrier。为提高性能,两个Write Barrier先放到队列中,异步处理

5. Full GC

CMS Full GC原因:Promotion FailureConcurrent Mode Failure,晋升老年代没足够连续空间,可能内存碎片导致;jvm觉得并发结束前堆就满,提前触发Full GC。是多线程STW的Mark-Compact过程,需避免或者降低频率。

G1:Full GC对所有region做Evacuation-Compact(避免FullGC)单线程STW,耗时。原因(类似):1. Evacuation没有足够to-space放晋升对象;2. 完成前空间耗尽。

6.算法:

CMS标记—清理G1复制,保证不产生多余的碎片。

7.G1停顿时间可控: 

目的:减少STW时间,提高吞吐量

提供关键:

避免全域收集,有限时间内高效。G1跟踪各个Region里面的垃圾堆积的价值大小(回收获得空间大小及回收所需时间), 维护优先列表,价值最大Region先(Garbage-First来由)。

运作过程

你可能感兴趣的:((9)G1算法,及CMS比较)