G1面经粗解
现在G1的文章要么讲解的太深,要么讲的太浅不够面试。所以这篇就简单粗解一下G1的工作原理和大概率会被问到的面试点。具体深入内容 本人目前能力有限 可自行扩展,有不对之处 请评论指正。/拱手
G1的引入
因为Serial 和 Parallel 和 CMS都已经是过去式了,大家简单了解一下他们的发展就可以了,先要去了解GC历史上的复制算法,标记法的产生和优化。| G1是Java9开始默认的GC回收器。未来的GC回收器是ZGC
G1内存布局
G1是用在大内存堆(4-6G)的场景。(因为可以使用空间换取时间的方式解决Old和Eden的相互引用。此为后话)
Region
将内存空间划分为2048个大小相等独立的Region,每个Region的大小可以设定,但是Region的范围必须是1-32MB,且是2的n次幂
- 新生区:Eden
- 幸存区:Survivor
- 老年区:Old + Humongous
可以看到Region也是分为这三个,但是他们不是连续的。介绍一下我们的新朋友:Humongous,它是属于老年区的,当对象范围超过50%就会放入Humongous Region 中,对象过大时,好几个Region它也是连续。
工作原理
话不多说咱们直接看工作原理,当中的问题会中途提出并解决。
进行GC回收的时候不是无序回收整个堆,而是选择一个Collection Set(CS)来存放需要回收的Region。
G1有三种回收策略
- YoungGC
- MixedGC
- FullGC
YoungGC
发生在年轻代的回收算法,除了巨型对象都是在eden region 中分配内存,当所有的eden region 都被耗尽无法申请内存的时候,就会触发YoungGC ,G1停止应用程序的执行STW(STW指的是系统暂停所有正在运行的线程,以便进行垃圾回收操作)。
回收过程:
- 扫描根:根引用连同RS(Remember Set)记录的外部应用作为扫描存货对象的入口
- 更新Rs:处理 dirty card queue 更新RS,此后RS精确反应对象的引用关系
- 处理RS:识别被老年代对象指向Eden中的对象,这些被指向的对象认为是存活对象,需要回收分区放入Young Cset进行回收
- 复制对象:Eden 区内存段中存活的对象会被复制到Survivor区,Survivor区内存段中存货的对象如果年龄未达到阈值,年龄会+1,达到阈值之后,会被复制到Old区的Region,如果Survivor空间不够,Eden 的部分数据会直接晋升到老年代空间。
- 处理引用:处理Sofr,Weak,等引用,最终清空Eden。
Card Table 和 Remembered Set
欸!有同学看到这里了,什么是Rs?还记得我们之前说的Eden和Old相互引用的问题吗?
如图,如果Old的B 引用了Eden中的E,那么B对应的Card Table就会记录在Old的Remembered Set
Card Table
- 表中的每个entry覆盖512Byte的内存空间
- 当对应的内存空间发生改变时,标记为dirty
RememberedSet
- 指向Card Table中的对应entry
- 可找到具体内存区域
时间换空间
- 用额外的空间维护引用信息
- 5%~10% memory overhead,带来5-10%的内存浪费(内存大,问题不大)
ConcurrentMark
G1是如何并发+并行执行标记的?
- 初始标记:标记从根节点直接可达的对象,这个阶段是STW的,并且会触发一次年轻代。
- 并发标记(ConcurrentMark):在整个堆中进行并发标记,可能被YoungGC中断。会计算每个区域的对象存活,即每个区域的对象活性,即区域中存货对象的比例,若区域中的所有对象都是垃圾,则这个区域会被立即回收,给浮动垃圾准备出更多的空间,把需要收集的Region放入Cset
- 最终标记:为了修正正在并发标记期间因用户程序继续运作而导致标记产生的那一部分分标记记录,虚拟机将这段时间对象变化记录在线程的RememberSet中,这个阶段需要暂停线程,但是可并行执行。
- 筛选回收:并发清理阶段,首先对CSet中各个Region中的回收价值和成本进行排序,根据用户期望的GC停顿时间来指定回收计划也需要STW.
我们G1是如何在不暂停应用线程的情况下,进行标记的?
三色标记法:
通过把黑色引用的对象标记为灰色,重复执行这个算法。
直到全部都是黑色。
但是会发生LostObjectProblem
比如在某一时刻。C对象被让到A引用了。会导致C无法被正常回收。
如何解决?SATB(Snaphot-At-The-Beginnig)开始快照。
B.c=null,当C指针被删除的时候,G1认为C仍是活对象,
保持在marking阶段开始的Object graoh,C仍然被remark阶段处理,但是可能产生浮动垃圾。
FullyGC
对象内存分配速度过快,Mixed GC来不及回收,导致老年代被填满,就会触发一次G1的Full GC算法,就是单线执行的垃圾回收器,会导致异常长时间的暂停时间,要尽量避免,
产生Full GC的原因是
- 晋升时没有最够的空间存放晋升对象
- 并发处理过程完成之前空间耗尽。
G1 记录每个阶段的时间用于自动调优
记录Eden/Survivor的数量和GC时间
根据暂停目标自动调整Region的数量
l GC的原因是
- 晋升时没有最够的空间存放晋升对象
- 并发处理过程完成之前空间耗尽。
G1 记录每个阶段的时间用于自动调优
记录Eden/Survivor的数量和GC时间
根据暂停目标自动调整Region的数量
暂停目标越短,Eden数量越少