JVM面试高频考点:由浅入深带你了解G1垃圾回收器!!!

举报
Code皮皮虾 发表于 2021/07/12 17:56:11 2021/07/12
【摘要】 JVM面试高频考点:由浅入深带你了解G1垃圾回收器!!!

G1垃圾回收器介绍

G1垃圾回收器是一款主要面向服务端应用的垃圾收集器。作为垃圾回收器技术发展史上里程碑的成果,G1垃圾回收器不同于以往的垃圾回收器,首先是思想上的转变,如下图:

G1对于Java堆的划分
在这里插入图片描述

上面的图,小伙伴们第一次看可能不咋明白,因为各位还不了解G1,看看下面的话,应该就差不多了。


G1垃圾回收器对于Java堆区域的划分不同于以往我们对Java对区域划分的认知

以往对于Java堆区域的划分为:新生代和老年代,新生代又划分为 Eden区和 Survivor区,Survivor区又分为 from区和 to区。

在这里插入图片描述


但是现在,G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的Java堆空间划分为多个大小相等的独立区域(Region),每个Region都可以成为 Eden空间、Survivor空间、老年代空间。


这种思想上的转变和设计,使得G1可以面向堆内存任何部分来组成回收集来进行回收,衡量标准不再是它属于哪个分代,而是哪块内存存放的垃圾最多,回收收益最大,这就是G1收集器的 Mixed GC模式,即混合GC模式。


Region还有一类特殊的 Humongous 区域专门用来存储大对象。G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象如果是那些超过了整个Region容量的超大对象,将会放在连续 N 个 Humongous Region区域。

Region的取值范围为 1M ~ 32M

Region的默认个数为 2048个

-XX:G1HeapRegionSize = N


G1这么做看起来是由一种焕然一新的感觉,但细心的小伙伴可能已经发现,如果 Region之间存在跨区引用对象,那这些对象如何解决?

  1. 不管是G1还是其他分代收集器,JVM都是使用 记忆集(Remembered Set) 来避免全局扫描。
  2. 每个Region都有一个对应的记忆集。
  3. 每次Reference类型数据写操作时,都会产生一个 写屏障(Write Barrier)暂时去终止操作
  4. 然后检查将要写入的引用 指向的对象是否和该Reference类型数据在不同的 Region(其他收集器:检查老年代对象是否引用了新生代对象)
  5. 如果不同,通过 卡表(Card Table)把相关引用信息记录到引用指向对象的所在Region对应的记忆集(Remembered Set) 中
  6. 当进行垃圾收集时,在GC Roots枚举范围加上记忆集;就可以保证不进行全局扫描了。

G1的记忆集可以理解为一个哈希表,Key就是别的Region的起始地址,Value就是卡表的索引号集合。

在这里插入图片描述

因为G1将Java堆划分为一个个Region的缘故,而Region数量相比于传统分代数量明显多得多,所以G1相比于传统的垃圾回收器来说,需要消耗相当于Java堆容量 10%~ 20%的额外空间来维持收集器的工作。




G1 垃圾回收器工作流程

  • 初始标记(Initial Marking):这阶段仅仅只是标记GC Roots能直接关联到的对象并修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确的可用的Region中创建新对象,这阶段需要停顿线程,但是耗时很短。而且是借用进行Minor GC的时候同步完成的,所以G1收集器在这个阶段实际并没有额外的停顿。

  • 并发标记(Concurrent Marking)从GC Roots开始对堆的对象进行可达性分析,递归扫描整个堆里的对象图,找出存活的对象,这阶段耗时较长,但是可以与用户程序并发执行。当对象图扫描完成以后,还要重新处理SATB记录下的在并发时有引用变动的对象。

  • 最终标记(Final Marking):对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的 SATB 记录。

  • 筛选回收(Live Data Counting and Evacuation)负责更新 Region 的统计数据,对各个 Region 的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划。可以自由选择多个Region来构成会收集,然后把回收的那一部分Region中的存活对象==复制==到空的Region中,在对那些Region进行清空。

除了并发标记外,其余过程都要 STW



G1和CMS的区别

  • G1从整体上来看是 标记-整理 算法,但从局部(两个Region之间)是复制算法。而CMS是 标记-清除算法 所以说,G1不会产生内存碎片,而CMS会产生内存碎片
  • CMS使用了 写后屏障来维护卡表,而G1不仅使用了写后屏障来维护卡表,还是用了 写前屏障来跟踪并发时的指针变化情况(为了实现原始快照)。
  • CMS对Java堆内存使用的是传统的 新生代和老年代划分方法,而G1使用的全新的划分方法。
  • CMS收集器只收集老年代,可以配合新生代的Serial和ParNew收集器一起使用。G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用
  • CMS使用 增量更新解决并发标记下出现的错误标记问题,而G1使用原始快照解决




最后

我是 Code皮皮虾,一个热爱分享知识的 皮皮虾爱好者,未来的日子里会不断更新出对大家有益的博文,期待大家的关注!!!

创作不易,如果这篇博文对各位有帮助,希望各位小伙伴可以==一键三连哦!==,感谢支持,我们下次再见~~~

更多精彩内容分享,请点击 Hello World (●’◡’●)


欢迎关注,更多大厂面试题等待着您的到来!😁
image.png

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。