细数G1GC

G1GC相当复杂,一篇文章的话很难说清楚,并且长篇冗杂,难读。本文旨在将G1GC中的部分点Get到,也很难全面,如果错误,请帮忙指正,多谢。

一、G1GC的目的

针对服务器应用(大heap内存、多核)进行垃圾收集,为了同时兼顾吞吐量和停顿时间而生。

二、特点

分区、分代、适用多核大heap内存、高吞吐、低停顿

三、如何实现对吞吐量和停顿时间的兼顾

1、技术手段

1)region划分
将整个heap划分为大小相等的region,每个region内的heap内存地址连续。

2)停顿时长预测模型
通过该模型来确定回收哪些region,以满足用户指定的可停顿时间。

3)并发全局标记
和应用程序并发执行,标记整个heap中存活对象。

4)Garbage-First
优先回收垃圾最多的region,以获取最大空间释放。

5)拷贝压缩
具体回收时,将Object从一个或多个region拷贝到单个heap region上,并对内存进行压缩整理。这一过程多线程并行执行,因此可减小停顿时间并提高吞吐量。

2、具体过程

1)region划分
将整个heap划分为大小相等的region,一组空region为逻辑上的yong region,另一组为逻辑上的old region,yong region包含Eden、survivor区,也都是由region为单位组成。

2)对象分配
对象在yong region 的Eden上分配

3)触发GC
当年轻代满,无法为新对象分配空间时,触发yong GC。老年代空间占用达一定比例时触发old GC。yong GC和old GC可能同时发生(mixed GC)。当没有空的region供对象拷贝(回收时进行的复制压缩)过去时,触发full GC。

4)垃圾回收
初始标记
SATB(snapshot-at-the-beginning),在并发标记之前快照,记录live对象
并发全局标记
重标记
复制整理

注:STAB这是一种增量标记算法,为的是减少重标记的耗时,以及在并发标记阶段很容易识别垃圾对象。

3、停顿STW(Stop the world)发生的阶段
1)minor GC
2)一个是重标记
并发标记阶段可能有新的对象死亡
3)一个是清理垃圾时复制压缩(也就是将活对象拷贝到new region中)。
需要停止应用,以寻找空的region供拷贝活对象

四、数据结构

1、Remembered Set

Java HotSpot VM使用字节数组来当卡表(Card Table),每个字节代表一个卡片,每个卡片代表一个heap地址范围512bytes,即region内存最小可用粒度

分代收集通常会出现某代在进行垃圾收集而某代不进行垃圾收集的情况。年轻代正在进行垃圾收集,而老年代则未进行垃圾收集就是一个例子。那么,垃圾收集器就需要知道,哪里有从老年代指向年轻代的指针。记录这一信息的结构就叫Remembered Set。卡表便是特殊类型的Remembered Set。

1)说明:
每个region都有一个Remembered Set。记录该region中的对象被跨代引用的情况。也就是说这个region会记录下别的哪些Region有指向自己的指针(别的谁引用了我)。

RSet类似一个Hash Table,key为引用自己的region的地址,value为对应的卡片索引。

2)作用:
避免G1做GC时整堆扫描。具体来讲,是为了避免old generation的全部扫描。
Yong GC时,RSet记录的old->yong的引用关系,只需枚举有RSet记录old region。
Mixed GC时,old region的RSet记录了old->old的引用关系,yong->old的引用由扫描yong generation得到,也避免了扫描整个old region。

在并发整理阶段,被收集滕空后的regions被加入到free region list中,并将这些region从Remembered Set中清除。

2、Collection Set

G1利用停顿时长预测模型来判断在指定的停顿时间内能完成多少收集工作。本次收集完成后,会选择下一次要收集的regions并加入到collection set当中,这其中也包括yong regions。正是通过选择yong region的数量来发挥控制停顿时长的作用,具体体现在调节Eden和survivor大小。

五、并发优化线程

并发优化线程:根据需要运行,遍历卡表被应用写入弄脏的条目,以更新跨region的引用。

作用:和post-write barrier共同作用,维护RSet的引用关系更新。

六、分代GC

1、yong GC

1)触发条件
当年轻代满,无法为新对象分配空间时,触发yong GC

2)特点
Stop the world

3)GC的目标region
来自上一次收集过程中由G1加入到Collection Set当中的eden and survivor regions

3)做法
将这些region中的活对象根据其age,拷贝到survivor region,或者拷贝到old region。如果是拷贝到survivor region,那么会被加入到Collection Set当中,供下一次GC收集。

2、mixed GC

1)触发条件
-XX:G1MixedGCLiveThresholdPercent=85(默认)
表示当老年代中region使用率达到85%时,垃圾回收也要包括老年代。即mixed GC。

2)收集过程

  • 将一定数量的old region 添加到Eden区和survivor区,前边说过,这样是为调节年轻代的大小,来控制停顿时长。
  • 回收足够多的old region。

3)回收方式
多线程并行收集

4)并发标记周期开始时间
整个Java heap内存占用比例达到InitiatingHeapOccupancyPercent配置的百分比时,默认为45%

七、标记周期组成

1、初始标记
标记在yong GC中加入到Collection Set的region,作为Root region。这一部分借yong GC的STW时段完成。

2、Root region扫描
扫描上一步中的region,找被老年代引用的对象,并标记这些引用对象。
前边文章也说过,这一阶段要在下一次yong GC之前完成,因为yong GC又会有新的region加入到本阶段需要扫描的Collection Set当中。

3、并发标记
这一阶段并发标记整个heap中的可达对象。可被yong GC(STW)打断,因为即使产生了新的对象,对重新运行时标记也没有影响。

4、重标记
本阶段STW,遍历SATB缓冲区,标记并发标记阶段未访问到的存活对象并执行引用处理。到此,一个标记周期结束。

5、清理
这一阶段也是STW(暂停应用程序)
主要工作:进行Rset梳理。整理堆分区,识别完全空闲的分区直接清除,并选出下一个Mixed GC的候选分区。

清理的最后阶段,重置和返还空闲分区到free list的工作是和应用线程并发执行的。

八、并发与并行

上述3中的涉及STW的阶段,均由多线程并行执行,线程数可由如下参数设置
-XX:ParallelGCThreads=n
此时应用程序停止执行,所以要充分利用多核进行处理,尽可能的让程序尽快运行。

并发标记阶段,由多线程并行执行,线程数可由如下参数设置
-XX:ConcGCThreads=n
建议设置为ParallelGCThreads数量的1/4,因为此时是和应用程序并发执行,这样也是尽量保证程序的吞吐量。

九、参考

https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html#garbage_first_garbage_collection
https://tech.meituan.com/2016/09/23/g1.html
https://blog.csdn.net/coderlius/article/details/79272773

发布了95 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43878293/article/details/103376392