G1垃圾收集器(Garbage-First Garbage Collector)
介绍
G1垃圾收集器是一种针对多核、大内存计算机的垃圾收集器。其主要目标是即使不做任何配置,也能在很大程度上达成垃圾收集停顿时长目标,同时维持高吞吐量。G1垃圾收集器试图在特定应用程序及环境下维持延迟和吞吐量的最佳平衡。“特定”程序及环境一般有如下特性:
数十GB堆内存及以上,其中超过50%的区域包含实时数据。
对象分配、换代频率极其随机。
堆内存碎片化现象十分严重。
目标停顿时间预计不超过几百毫秒,避免因垃圾回收停顿太长时间。
替换掉了并发标记清除收集器(Concurrent Mark-Sweep (CMS) collector)。(自JDK9,G1代替 Parallel GC成为JDK默认垃圾收集器)
G1收集器通过几种方式实现高性能、高可用性。具体方式会在接下来分几部分介绍。
启用G1
G1垃圾收集器是默认收集器,你一般情况下无须做任何操作。(在命令行使用命令-XX:+UseG1GC
可显式启用)
基本概念
G1是一种分代、增量、并行、部分并发、全局停止、实行对象转移的垃圾收集器,每次全局停止期间会实时监控停顿时长目标。 和其他收集器类似,G1收集器将堆内存分为(虚拟)年轻代和老年代。G1回收内存空间时着重关注效率最高的年轻代,偶尔回收老年代内存空间。
为了提高吞吐量,某些操作只会在全局停止期间才会进行。一些操作(比如全堆标记(global marking)等涉及整个堆的操作)在应用程序停止时进行会耗费更多时间,因此这类操作会与应用程序并行、并发执行。为缩短内存回收时全局停止的时长,G1收集器会已增量的方式分阶段、并行执行空间回收。 G1收集器会通过跟踪既往应用行为和垃圾收集停顿,建立反映相应回收成本的模型来保证预计停顿时长的准确性。该收集器利用这个模型分析之前停顿时所做工作。例如,G1收集器会首先回收回收效率最高的内存区域(即大部分区域都由垃圾对象占据,Garbage-First
之名也由此而来)。
G1收集器回收内存主要靠对象转移:将预选内存区域内的发现的活动对象整理后复制到新的内存区域。转移结束后,活动对象先前占据的内存空间可以供程序重新分配。
G1垃圾收集器并不是实时的。它会尝试在一段时间内尽力达成设置的停顿时长目标,但不能保证某个停顿期的停顿时长一定能符合目标。
堆内存布局
G1收集器将堆内存划分为一个个大小相等的子区域,每个子区域都覆盖一段连续的虚拟内存区,如图9-1所示。子区域是内存分配、内存回收的基本单位。在任一时刻,这样的区域可能存在两种状态:空闲(浅灰色)、分配给年轻代或老年代。当应用程序请求内存时,内存管理器会将空闲内存区域分配出去。内存管理器将这些子区域分配到某一代际,然后将其作为空闲区域返回给应用程序供其分配。
图 9-1 G1垃圾收集器堆内存布局
年轻代由Eden区(红色)和Survivor区(红色带S标记)。这些区域和其他垃圾收集器中的对应内存区域功能大体一致,区别在于,在G1内存布局下,这些内存区在内存中所占空间并不连续。图中所有的浅蓝色区域即构成了老年代。老年代中涵盖数块子区域的内存区被称为巨型对象区域(Humongous Region)(浅蓝色带H标记)。
应用程序为对象分配内存时永远只使用某一Eden区子区域,不过巨型对象会被直接分配到老年代中。
G1垃圾收集器在暂停期间可以回收整个年轻代的空间,此外,在任何暂停期间均可回收需要回收的老年代内存区域集合。在暂停期间,G1收集器会将当前待回收子区域集中的对象复制到堆中一个或多个不同区域。某一对象的目标区域取决于该对象的来源:整个年轻代会被复制到Survivor区或老年代区域,老年代的对象会根据老化(Aging)程度复制到其他不同的老年代区域。
垃圾回收周期
抽象来看,G1收集器的垃圾收集过程分两种阶段,这两个阶段交替进行。在young-only阶段,收集器将年轻代中的对象复制到老年代中的空闲区域,直至填满。在空间回收(space-reclamation)阶段,G1收集器以增量的方式回收老年代空间,并同时进行年轻代内存回收。然后,循环从young-only阶段重新开始。
图 9-2 垃圾回收周期总览
上图展示了G1收集器两个阶段执行序列以及期间可能出现的停顿。图中填充的圆圈代表垃圾收集的暂停:蓝色圆圈代表young-only阶段,橙色圆圈代表标记(marking)引起的暂停,红色圆圈代表混合收集(mixed collection)暂停。所有暂停通过两个箭头串联在一起,形成一个循坏:箭头分别代表young-only阶段和混合收集(mixed collection)阶段。young-only阶段从几个用蓝色小圆圈表示的young-only垃圾收集开始。当老年代中的对象占用率达到initiatingheapoccuancypercent
定义的阈值之后,下一次垃圾收集暂停将变成初始标记垃圾收集暂停,即图中较大的蓝色圆圈。除了执行与其他young-only阶段暂停相同的工作之外,该停顿期间,收集器还会为并发标记做些准备工作。
在并发标记和Remark导致的暂停(第一个大的橙色圆圈,此时G1收集器完成标记)之间,可能会同时发生young-only暂停。之后,在Cleanup阶段导致暂停之前,可能还会发生young-only垃圾收集。在Cleanup阶段引发的暂停之后,将会进行最终young-only阶段垃圾收集。在空间回收阶段,可能会出现一系列的混合收集(即图中的红色圆圈)。G1收集器在进行空间回收时为了尽可能提高效率,young-only阶段中的混合垃圾收集暂停通常少于young-only暂停。
下面的列表详细描述了G1垃圾收集周期的各个阶段、它们引发的暂停以及阶段之间的转换细节:
-
Young-only阶段:该阶段开端,G1会进行一系列普通年轻代垃圾收集,将年轻代的对象提升到老年代。当老年代的占用率达到某个阈值(即初始堆占用率阈值)时,Yong-only阶段到空间回收阶段的转换就开始了。此时,G1收集器启动名为Concurrent Start的年轻代垃圾收集。
Concurrent Start: 此类收集除了会执行一次普通的年轻代垃圾收集外还会启动标记过程。并发标记会找出老年代中所有后续空间回收阶段中应保留的当前可达(活动)对象。在标记进行过程中可能会发生普通的年轻代收集。两个需要全局停止的操作(Remark和Cleanup)结束后,整个标记过程才宣告结束。
Remark:该过程会处理全局引用信息、执行类卸载、回收完全处于空闲状态的子内存区域、清理内部数据结构。在Remark和Cleanup之间,G1收集器会收集信息,以便之后能够以并发的方式回收选定的老年代区域中的空闲空间(该过程最终在Cleanup暂停中完成)。
Cleanup:该过程决定了之后是否进入空间回收阶段。如果进入空间回收阶段,则会以一个Prepare Mixed年轻代收集结束Yong-only阶段。
Space-reclamation phase:该阶段由多个混合垃圾收集组成。除了年轻代子区域外,此阶段还会转移老年代子区域集合中的活动对象。当收集器认为转移更多的老年代子区域无法产生足够的空闲空间时,此段就结束了。
空间回收阶段结束之后,垃圾收集周期从另一个Young-only阶段重新开始。如果在应用程序收集活动对象信息时内存耗尽,G1收集器会像其他收集器一样立即停止所有应用线程,执行全堆垃圾收集(full GC)。
本文为此页面译文