JVM垃圾收集器(四) —— G1收集器

前面两篇文章主要是讲了新生代和老年代的垃圾收集器,本文就来介绍一下比较特殊的垃圾收集器——G1垃圾收集器

G1是一款面向服务端应用的垃圾收集器。

一、G1的特点:

1、并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。

2、分代收集:与其他收集器一样,分代概念在G1中依然得以保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。

3、空间整合:与CMS的“标记—清理”算法不同,G1从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。

4、可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。


二、内部执行原理:

在G1之前的其他收集器进行收集的范围都是整个新生代或者老年代。而G1是面向整个堆。
它将整个Java堆划分为多个大小相等的独立区域(Region),但是G1有一种优先级的概念,就是可回收空间比较大的region会优先进行回收,这也是G1收集器能在有限的时间活得最高回收率的原因。
G1内部每一个region都有一个remember set来记录region内对象的指针,从而有计划地避免回收时对整个堆进行扫描。


三、运作步骤:前两步和CMS是一样的

  • 初始标记(Initial Marking):仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时很短
  • 并发标记(Concurrent Marking):从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行
  • 最终标记(Final Marking):为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行
  • 筛选回收(Live Data Counting and Evacuation):首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段可以做到与用户程序一起并发执行,但是因为只回收一部分Region,所以时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。

导致两者差异的原因在于CMS采用的是标记-清除算法,而G1采用的是标记-整理算法 + Region的内存划分


四、G1收集器运行示意图:

这里写图片描述


本文的内容和图片参考自:《深入理解Java虚拟机:JVM高级特性与最佳实践》

猜你喜欢

转载自blog.csdn.net/Lin_wj1995/article/details/79978116