开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
垃圾回收器 Part2
上一节介绍了垃圾回收算法,和几种垃圾回收器,本节将开始介绍更加复杂的两种垃圾回收器G1和ZGC。首先开始介绍大名鼎鼎的G1垃圾回收器。
G1
该垃圾回收器通过参数 -XX:useG1GC开启。
这是一款面向服务端的垃圾回收器,主要适配于核数多和内存高的机器,在满足GC低停顿的同时还满足较高的吞吐量。适合存活对象较多而且机器内存较大(8G+)的情况。
特殊分区
G1消灭了传统的物理分区概念,它将堆分成多个大小相等的Region,JVM最多有2048个Region。一般来说Region的大小相当于堆大小除以2048,也就是4个G的堆每个Region占2M,Region的大小还可以通过参数 -XX:G1HeapRegionSize指定,但是通常使用推荐值。
虽然消灭了物理分区概念,但是仍然保留了年轻代和老年代的概念。Eden区,Survivor区和Old区不再是连续的物理内存,而是Region的集合。每个Region的身份都是动态变化的,有可能一个Region在GC前是年轻代,GC后就变成了老年代。
默认年轻代会占5%的堆内存,也就是说一个4G的堆其中会有200M左右的年轻代,也就是100个左右的Region。这个比例会在运行时不断调整上升,新生代最多不会超过堆内存的60%。年轻代的初始占比可以通过参数 -XX:G1NewSizePercent设置,参数 -XX:G1MaxNewSizePercent可以设置新生代占堆内存的最大占比。
传统的分区会将大对象分配在老年代中,但是G1将大对象单独分区,分在Humongous区中,避免占用老年代空间。对于大对象的判定标准就是这个对象如果超过了一个Region的50%就会划分为大对象。比如说每一个Region区2M,那么1M以上的对象就会判定为大对象。Humongous区可以横跨多个Region。Full GC会将三个区域一起回收。
回收过程
前面三个阶段和CMS阶段完全一致,其中初始标记和最终标记都是STW。最重要的是筛选回收。
筛选回收会对Region的回收价值和成本进行排序,根据用户期望的GC时间去进行回收。选择多个Region构成回收集,将决定回收的Region中存活的对象复制到空Region中,清理掉旧的Region。可以设定参数 -XX:G1MixedGCLiveThresholdPercent,存活对象低于该值的Region才会被回收,该值默认为85%。用户期望停顿时间可以用参数 -XX:MaxGCPauseMills指定。
筛选回收过程可以不是一次执行完毕,通过设定参数 -XX:G1MixedGCCountTarget可以回收一会儿,恢复系统运行然后再回收一会儿,避免单次停顿时间过长,该次数默认为8次。
可以看出G1使用的方法是标记复制法,因此不会像CMS那样清理后会产生大量的碎片。
除了能够并行回收提高用户体验外,G1垃圾回收器最大的优点就是能够设置期望的停顿时间,并且可以根据这个时间进行最优回收。但是并不是停顿时间越短越好,停顿时间要合理。如果停顿时间设置太短,会导致不断有垃圾累积,最后触发Full GC。
回收类型
G1垃圾回收器并不仅仅只有Minor GC和Full GC,还有一种特殊的Mixed GC
Minor GC:并不是说Eden区放满了就会触发Minor GC。前面提到新生代的比例会不断调整增加,在需要进行Minor GC后G1会计算回收的时间是否接近设定的期望停顿时间,如果远远小于该值,那么会继续增加新生代的Region,否则的话会进行回收
Mixed GC:并不是Full GC,当老年代空间到达参数 -XX:InitiatingHeapOccupancyPercent设定比例后会触发Mixed GC,默认为45%。它会回收所有的年轻代Region和根据期望停顿时间确定的部分老年代Region以及大对象区。在拷贝过程中如果没有足够的Region空间,将触发Full GC。当空闲的Region达到设定参数 -XX:G1HeapWastePercent占比的堆内存,就会停止Mixed GC,默认值为5%。
Full GC:会停止系统程序,采用单线程的方式进行标记、清理和整理,非常耗时。
ZGC
该垃圾回收器通过参数 -XX:useZGC开启。
这是一种JDK 11新加入的垃圾回收器,并且还在开发当中。它是为了支持TB量级的堆,并且控制最大GC停顿时间不超过10ms。目前ZGC暂时没有分代,目前只有单分代的版本,后续会继续优化。
分区概念
ZGC虽然没有分代的概念,但是保留了G1的Region,分为大,中,小三类Region。
小型Region:容量为2MB,用于放置小于256KB的对象。
中型Region:容量为32MB,用于放置大于256KB小于4M的对象。
大型Region:容量不固定,但是必须是2的倍数,并且该种类的Region只能存放一个对象,所以如果一个对象是4M那么大型Region可能会比中型Region更小。
NUMA-aware
传统的是UMA架构,也就是Uniform Memory Access Architecture。这表示只有一块内存,所有的处理器都去访问这一块内存,那么就会存在竞争问题,核心数越多,竞争就越激烈。而NUMA则是在这之前加上一个Non,代表着每个CPU都有对应的一块内存,并且这块内存离CPU最近,那么每个CPU优先访问该内存,效率就上升了。
NUMA在很多大型项目上运用比较广泛,ZGC可以自动感知NUMA架构并且充分利用NUMA特性。
颜色指针
颜色指针是ZGC的核心特性,过去垃圾回收器的GC信息都保存在对象头中,而ZGC则是保存在指针中。
整个颜色指针分为四个部分
Unused:18位,预留给未来使用
Finalizable:1位,表示只能被Finalizer对象访问
Remapped:1位,表示该对象没有指向需要GC的Region集合
Mark1:1位
Mark2:1位,和上面的Mark1都是用来辅助GC的
Object Address:42位,对象的地址
Mark1和Mark2都是为了辅助GC过程中的三色标记过程,三色标记的知识将在下一节分析。
由于ZGC涉及的底层原理比较多,包括转发表,三色标记,读写屏障等,下一节将集中讲解在垃圾回收过程中涉及到的原理,把原理都讲明白后,再仔细分析ZGC会更好理解。
总结
本节介绍了G1和ZGC垃圾回收器,其中ZGC将在下一节原理部分后继续深入研究,会对原理和ZGC的理解更加深刻。
介绍了几种垃圾回收器,其实可以总结一下我们什么时候应该选择什么样的垃圾回收器。
如果机器是单核的,那么选择Serial就足够了
如果机器内存小于4G,选择Parallel
4~8G可以选择ParNew+CMS
8G+可以选择G1
如果是几百G以上的内存可以考虑ZGC