面试官:这次怎么不说说G1垃圾回收器?考生:嗯,好吧考生:上次想起CMS垃圾回收器的缺点:会产生内存碎片&&需要预留空间考生:在处理这两个问题的时候,很有可能会造成停顿时间太长了。说白了,CMS的暂停时间是一个“不可预测”的候选者:而G1可以理解为CMS垃圾收集器上的一个“升级”候选者:G1垃圾收集器可以给你一个settingsetapausetimeyouwantStopWord,G1垃圾收集器会根据这个时间尽量满足你的候选人:前面介绍JVM堆的时候,我画了一张图。堆的内存分布以“物理”空间分隔前面提到的“分代”概念在G1垃圾收集器的世界里仍然是一个有效的候选者:比如新对象一般分配到Eden区,而对象在经过默认15次MinorGC的新生代还活着,会交给老年代等。考生:我来画一下G1垃圾收集器世界中的“堆”空间分布。G1中的每个region称为一个Regioncandidate:oldgeneration,newgeneration,Survivor等,不用我多说了吧?规则和CMS是一样的候选:在G1中,还有一个Humongous(大对象)区,其实就是用来存放特别大的对象(大于Region内存的一半)。候选:一旦没有找到对大对象的引用,可以直接在新生代MinorGC中回收。面试官:嗯……应聘者:其实稍微想一下就明白为什么要把“堆空间”“细分”成多个小区域。候选:像之前的垃圾收集器都是“物理”划分堆的候选:如果堆空间(内存)很大,每次“垃圾收集”需要回收一大片区域,收集时间就是一个候选不易控制:划分多个小区域后,很容易控制其回收这些“小区域”的“收集时间”。面试官:嗯……面试官:那我大概明白了。你说说它的GC过程怎么样?考生:嗯,在G1收集器中,主要可以分为MinorGC(YoungGC)和MixedGC,FullGC在一些特殊场景下可能会出现。考生:那我就先说MinorGC?面试官:嗯,那我们开始吧。候选:G1的MinorGC其实和上面说的垃圾收集器是同时触发的。候选:当Eden区满了,就会触发MinorGC。MinorGC也是StopTheWorld的候选:需要补充的是,在G1的世界中,新生代和老年代占用的堆空间并不是那么固定(会根据“最大停顿”动态确定time")Adjustment)考生:很高兴知道它会给我们提供参数进行配置。候选人:因此,动态改变年轻代Region的数量,可以“控制”MinorGC的开销。面试官:那么MinorGC呢?回收过程如何?能不能再详细一点考生:MinorGC我觉得可以简单分为三步:根扫描,更新&&处理RSet,复制对象考生:第一步应该很容易理解,因为和前面的差不多CMS考生:第二步涉及到“Rset”的概念面试官:恩...考生:上次讲CMS回收流程的时候,也讲了MinorGC,就是通过“Carttable”来避免fulltable老年代中候选对象的扫描:因为MinorGC回收的是新生代中的对象,但是如果老年代中有引用新生代的对象,那么这些老年代引用的对象也是候选对象,不能被回收:同样,这个问题在G1中也存在(毕竟是MinorGC)。CMS是卡表,G1解决“跨代引用”问题的存储一般称为RSetcandidate:只要记住RSet存储会存在于每个Region中,它记录的是当前Region中的“其他Region引用对象”Relationship"Candidate:对于新生代的Region,它的RSet只保存了老年代的引用(因为不需要保存新生代,我要自己做MinorGC)Candidate:对于老年代的Regiongeneration也就是说,它的RSet只会在oldgeneration中保存对它的引用(在G1垃圾收集器中,younggeneration会在oldgeneration回收之前被回收,所以不需要保存younggeneration的引用)面试官:嗯……候选人作者:看了第二步RSet的概念,应该很容易理解吧?Candidates:无非是处理RSet和scanning的信息,将老年代对象对年轻代对象的相关引用添加到GCRoots中,避免被回收。之后将存活的对象存放在“空的Survivor区”或者“OldGeneration”,其他Eden区用于清除候选:这里要提一下,G1中还有一个名词,叫做CSet。Candidate:它的全称是CollectionSet,保存了一次GC中“将要进行垃圾回收”的Region。CSet中所有存活的对象都会被转移到其他可用的RegionsCandidates:MinorGC结束时,软引用、弱引用、JNIWeak等引用都会被处理,收集结束。面试官:嗯,我明白了,不难面试官:我记得你前面提到过MixedGC,不如来谈谈这个过程吧?候选人:好的,没问题。候选:当堆空间占用达到一定阈值(默认45%,由参数决定)时会触发MixedGC候选:MixedGC依赖于“全局并发标记”统计后的Region数据它的流程和CMS很相似,步骤大致是:初始标记(STW)、并发标记、最终标记(STW)和清理(STW)。采访者:真的很像。能继续说说具体的过程吗?考生:嗯,还是要说明一下:MixedGC肯定会回收younggeneration,还会收集一些oldregion进行回收,所以是“mixed”GC。考生:首先是“初识”。这个过程“共享”了StopTheWorldofMinorGC(MixedGC肯定会发生MinorGC),复用了“扫描GCRoots”的操作。考生:这个过程中老年代和新生代都会扫描考生:总的来说,“初始标记”的过程比较快,毕竟没有回溯遍历面试官:……考生:接下来是”Concurrentmarking”,这个阶段不会停止worldCandidates:GC线程和用户线程一起执行,GC线程负责收集每个RegionCandidates中存活对象的信息Candidates:从GCRoots回溯寻找整个Region中的存活对象heap,比较耗时面试官:嗯……考生:接下来就是“remarking”阶段,和CMS一样,把那些在“concurrentmarkup”阶段发生变化的对象标记出来考生:是不是很简单?面试官:等一下。采访者:在“remarking”阶段,CMS应该以root身份重新扫描所有线程栈和整个新生代。面试官:据我了解,G1好像不是这样的。你懂吗?考生:嗯,G1确实不是这样的。在G1中,解决了“并发标记”阶段引起的引用变化问题,使用了SATB算法Candidate:可以简单理解为:GC开始时,为存活的对象做了一个“快照”的candidate:in“并发阶段”,每次引用关系发生变化时,记下旧的引用值考生:但是SATB算法有个小问题,就是:如果一开始G1认为是活着的,那么在这一次它不会在GC中被回收,即使这个对象在“并发阶段”可能已经变成了垃圾。Candidate:因此,G1也可能存在“浮动垃圾”的问题Candidate:但总体来说,对G1来说问题不大(毕竟它不追求一次清除所有垃圾,而是专注于StopTheWorldtime)面试官:嗯...考生:最后一个阶段是“清理”,这个阶段也会是StopTheWorld,主要是统计和重置标记状态考生:根据“停止预测模型”(其实就是设定的暂停time)来决定有多少个Regioncandidates来回收这个GC:一般来说,MixedGC会选择所有的younggenerationRegion,以及一些“回收价值高”的oldgenerationRegion(回收价值高的其实是垃圾(Multiple))的候选者进行收集:最后一次MixedGC清除或“复制”的候选:因此,一次collection不一定能收集到所有的垃圾,G1会根据停顿时间来选择Region的数量(:面试官:嗯,大致了解了面试官:G1fullGC什么时候发生?候选:如果MixedGC跟不上用户线程的内存分配速度,oldgeneration会被填满,无法继续MixedGC会降级为serialoldGC,收集整个GCheapcandidate:不过,这种场景还是比较少见的相比CMS,毕竟G1不存在CMS内存碎片的问题(:本文总结(G1垃圾收集器特性):从原来的“物理”代到现在的“逻辑”代,堆内存是“逻辑上”划分为多个region,使用CSet存储可恢复Region的集合,使用RSet处理跨代引用(注:RSet不保留年轻代相关的引用关系)G1可以简单分为:MinorGC、MixedGC、FullGC【Eden区满时触发】MinorGC回收过程可以简单分为:(STW)scanGCRoots,Update&&processRset,copyandclear【当整个堆空间被占用时触发一定比例】MixedGC靠“全局并发标记”得到CSet(可回收Region),然后“复制清空”R在描述G1的原理时,从宏观上看G1其实是“全局的”并发标记”和“复制幸存的对象”。SATB算法用于处理对象引用在“并发标记”阶段可能被修改的问题。提供了一个暂停时间参数供用户设置(G1会尽量满足暂停时间)来调整GC时回收的Region数量)欢迎关注我的微信公众号【Java3y】聊聊Java面试,在线面试官系列持续更新中!【在线面试官-手机]系列,每周两篇,持续更新中!【在线面试官-电脑】系列每周两篇持续更新中!原创不易!!一连求三!!
