1

什么?面试官问我G1垃圾收集器?

 2 years ago
source link: https://zhuanlan.zhihu.com/p/431908205
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

什么?面试官问我G1垃圾收集器?

面试官要不这次来聊聊G1垃圾收集器?

候选者:嗯嗯,好的呀

候选者:上次我记得说过,CMS垃圾收集器的弊端:会产生内存碎片&&空间需要预留

候选者:这俩个问题在处理的时候,很有可能会导致停顿时间过长,说白了就是CMS的停顿时间是「不可预知的」

候选者:而G1又可以理解为在CMS垃圾收集器上进行”升级”

候选者:G1 垃圾收集器可以给你设定一个你希望Stop The Word 停顿时间,G1垃圾收集器会根据这个时间尽量满足你

候选者:在前面我在介绍JVM堆的时候,是画了一张图的。堆的内存分布是以「物理」空间进行隔离

v2-2ed4eecaa83d5344fe8e4f1864a1790c_720w.jpg

候选者:在G1垃圾收集器的世界上,堆的划分不再是「物理」形式,而是以「逻辑」的形式进行划分

候选者:不过,像之前说过的「分代」概念在G1垃圾收集器的世界还是一样奏效的

候选者:比如说:新对象一般会分配到Eden区、经过默认15次的Minor GC新生代的对象如果还存活,会移交到老年代等等…

候选者:我来画下G1垃圾收集器世界的「堆」空间分布吧

v2-669ab989756f3aafe7d85b468d01a2ac_720w.jpg

候选者:从图上就可以发现,堆被划分了多个同等份的区域,在G1里每个区域叫做Region

候选者:老年代、新生代、Survivor这些应该就不用我多说了吧?规则是跟CMS一样的

候选者:G1中,还有一种叫 Humongous(大对象)区域,其实就是用来存储特别大的对象(大于Region内存的一半)

候选者:一旦发现没有引用指向大对象,就可直接在年轻代的Minor GC中被回收掉

面试官:嗯…

候选者:其实稍微想一下,也能理解为什么要将「堆空间」进行「细分」多个小的区域

候选者:像以前的垃圾收集器都是对堆进行「物理」划分

候选者:如果堆空间(内存)大的时候,每次进行「垃圾回收」都需要对一整块大的区域进行回收,那收集的时间是不好控制的

候选者:而划分多个小区域之后,那对这些「小区域」回收就容易控制它的「收集时间」了

面试官:嗯…

面试官那我大概了解了。那要不你讲讲它的GC过程呗?

候选者:嗯,在G1收集器中,可以主要分为有Minor GC(Young GC)和Mixed GC,也有些特殊场景可能会发生Full GC

候选者:那我就直接说Minor GC先咯?

面试官:嗯,开始吧

候选者:G1的Minor GC其实触发时机跟前面提到过的垃圾收集器都是一样的

候选者:等到Eden区满了之后,会触发Minor GC。Minor GC同样也是会发生Stop The World的

候选者:要补充说明的是:在G1的世界里,新生代和老年代所占堆的空间是没那么固定的(会动态根据「最大停顿时间」进行调整)

候选者:这块要知道会给我们提供参数进行配置就好了

候选者:所以,动态地改变年轻代Region的个数可以「控制」Minor GC的开销

面试官嗯,那Minor GC它的回收过程呢?可以稍微详细补充一下吗

候选者:Minor GC我认为可以简单分为为三个步骤:根扫描、更新&&处理 RSet、复制对象

候选者:第一步应该很好理解,因为这跟之前CMS是类似的,可以理解为初始标记的过程

候选者:第二步涉及到「Rset」的概念

面试官:嗯…

候选者:从上一次我们聊CMS回收过程的时候,同样讲到了Minor GC,它是通过「卡表」(cart table)来避免全表扫描老年代的对象

候选者:因为Minor GC 是回收年轻代的对象,但如果老年代有对象引用着年轻代,那这些被老年代引用的对象也不能回收掉

候选者:同样的,在G1也有这种问题(毕竟是Minor GC)。CMS是卡表,而G1解决「跨代引用」的问题的存储一般叫做RSet

候选者:只要记住,RSet这种存储在每个Region都会有,它记录着「其他Region引用了当前Region的对象关系」

候选者:对于年轻代的Region,它的RSet 只保存了来自老年代的引用(因为年轻代的没必要存储啊,自己都要做Minor GC了)

候选者:而对于老年代的 Region 来说,它的 RSet 也只会保存老年代对它的引用(在G1垃圾收集器,老年代回收之前,都会先对年轻代进行回收,所以没必要保存年轻代的引用)

面试官:嗯…

候选者:那第二步看完RSet的概念,应该也好理解了吧?

候选者:无非就是处理RSet的信息并且扫描,将老年代对象持有年轻代对象的相关引用都加入到GC Roots下,避免被回收掉

候选者:到了第三步也挺好理解的:把扫描之后存活的对象往「空的Survivor区」或者「老年代」存放,其他的Eden区进行清除

候选者:这里要提下的是,在G1还有另一个名词,叫做CSet。

候选者:它的全称是 Collection Set,保存了一次GC中「将执行垃圾回收」的Region。CSet中的所有存活对象都会被转移到别的可用Region上

候选者:在Minor GC 的最后,会处理下软引用、弱引用、JNI Weak等引用,结束收集

面试官:嗯,了解了,不难

面试官我记得你前面提到了Mixed GC ,要不来聊下这个过程呗?

候选者:好,没问题的。

候选者:当堆空间的占用率达到一定阈值后会触发Mixed GC(默认45%,由参数决定)

候选者:Mixed GC 依赖「全局并发标记」统计后的Region数据

候选者:「全局并发标记」它的过程跟CMS非常类型,步骤大概是:初始标记(STW)、并发标记、最终标记(STW)以及清理(STW)

面试官:确实很像啊,你继续来聊聊具体的过程呗?

候选者:嗯嗯,还是想说明下:Mixed GC它一定会回收年轻代,并会采集部分老年代的Region进行回收的,所以它是一个“混合”GC。

候选者:首先是「初始标记」,这个过程是「共用」了Minor GC的 Stop The World(Mixed GC 一定会发生 Minor GC),复用了「扫描GC Roots」的操作。

候选者:在这个过程中,老年代和新生代都会扫

候选者:总的来说,「初始标记」这个过程还是比较快的,毕竟没有追溯遍历嘛

面试官:…

候选者:接下来就到了「并发标记」,这个阶段不会Stop The World

候选者:GC线程与用户线程一起执行,GC线程负责收集各个 Region 的存活对象信息

候选者:从GC Roots往下追溯,查找整个堆存活的对象,比较耗时

面试官:嗯…

候选者:接下来就到「重新标记」阶段,跟CMS又一样,标记那些在「并发标记」阶段发生变化的对象

候选者:是不是很简单?

面试官:且慢

面试官CMS在「重新标记」阶段,应该会重新扫描所有的线程栈和整个年轻代作为root

面试官据我了解,G1好像不是这样的,这块你了解吗?

候选者:嗯,G1 确实不是这样的,在G1中解决「并发标记」阶段导致引用变更的问题,使用的是SATB算法

候选者:可以简单理解为:在GC 开始的时候,它为存活的对象做了一次「快照」

候选者:在「并发阶段」时,把每一次发生引用关系变化时旧的引用值给记下来

候选者:然后在「重新标记」阶段只扫描着块「发生过变化」的引用,看有没有对象还是存活的,加入到「GC Roots」上

候选者:不过SATB算法有个小的问题,就是:如果在开始时,G1就认为它是活的,那就在此次GC中不会对它回收,即便可能在「并发阶段」上对象已经变为了垃圾。

候选者:所以,G1也有可能会存在「浮动垃圾」的问题

候选者:但是总的来说,对于G1而言,问题不大(毕竟它不是追求一次把所有的垃圾都清除掉,而是注重 Stop The World时间)

面试官:嗯…

候选者:最后一个阶段就是「清理」,这个阶段也是会Stop The World的,主要清点和重置标记状态

候选者:会根据「停顿预测模型」(其实就是设定的停顿时间),来决定本次GC回收多少Region

候选者:一般来说,Mixed GC会选定所有的年轻代Region,部分「回收价值高」的老年代Region(回收价值高其实就是垃圾多)进行采集

候选者:最后Mixed GC 进行清除还是通过「拷贝」的方式去干的

候选者:所以,一次回收未必是将所有的垃圾进行回收的,G1会依据停顿时间做出选择Region数量(:

面试官:嗯,过程我大致是了解了

面试官那G1会什么时候发生full GC?

候选者:如果在Mixed GC中无法跟上用户线程分配内存的速度,导致老年代填满无法继续进行Mixed GC,就又会降级到serial old GC来收集整个GC heap

候选者:不过这个场景相较于CMS还是很少的,毕竟G1没有CMS内存碎片这种问题(:

本文总结(G1垃圾收集器特点):

  • 从原来的「物理」分代,变成现在的「逻辑」分代,将堆内存「逻辑」划分为多个Region
  • 使用CSet来存储可回收Region的集合
  • 使用RSet来处理跨代引用的问题(注意:RSet不保留 年轻代相关的引用关系)
  • G1可简单分为:Minor GC 和Mixed GC以及Full GC
  • 【Eden区满则触发】Minor GC 回收过程可简单分为:(STW) 扫描 GC Roots、更新&&处理Rset、复制清除
  • 【整堆空间占一定比例则触发】Mixed GC 依赖「全局并发标记」,得到CSet(可回收Region),就进行「复制清除」
  • R大描述G1原理的时候,从宏观的角度看G1其实就是「全局并发标记」和「拷贝存活对象
  • 使用SATB算法来处理「并发标记」阶段对象引用可能会修改的问题
  • 提供可停顿时间参数供用户设置(G1会尽量满足该停顿时间来调整 GC时回收Region的数量

我最近一直在连载《对线面试官》系列,目前已经连载38篇啦!一个说人话的面试系列!

【大厂面试知识点】、【简历模板】、【原创文章】电子书,共有1263页

我把这些上传到网盘,你们有需要直接下载就好了。做到这份上了,不会还想白嫖吧点赞转发又不用钱。

链接:pan.baidu.com/s/1pQTuKBYs… 密码:3wom

收藏等于白嫖,点赞才是真情!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK