Poison

G1 GC

在 Orcale 的官方网站中,对于 G1 GC 的介绍可以参见 The Garbage First Garbage CollectorGarbage-First Garbage Collector Tuning,其中关键点如下:

G1 收集器是一个服务端的垃圾收集器,适用于具有大内存的多处理器机器。它极有可能满足垃圾回收(GC)暂停时间目标,同时实现高吞吐量。整堆操作(例如全局标记)与应用程序线程同时执行。这样可以防止与堆或活动数据大小成比例的中断。

G1 收集器通过多种技术实现了高性能和暂停时间目标。

堆被划分为一组大小相等的堆区域,区域大小可以从 1 MB 到 32 MB 不等,具体取决于堆大小。目标是不超过 2048 个区域。Eden、Survivor、Old 是这些区域中的逻辑分组,它们的分布并不连续。G1 执行并发全局标记阶段,以确定整个堆中对象的活动性。标记阶段完成后,G1 知道哪些区域大部分为空。 它首先对这些区域进行收集,通常会产生大量的自由空间。这就是为什么这种垃圾收集方法称为 “垃圾优先” 的原因。 顾名思义,G1 将其收集和压缩活动集中在可能充满可回收对象(即垃圾)的堆区域中。G1使用暂停预测模型来满足用户定义的暂停时间目标,并根据指定的暂停时间目标选择要收集的区域数。

由 G1 标识为可回收的成熟区域是即将被收集的垃圾。G1 将对象从堆的一个或多个区域复制到堆上的单个区域,并且在此过程中,压缩和释放了内存。垃圾收集是在多处理器上并行执行的,以减少暂停时间并增加吞吐量。因此,对于每次垃圾收集,G1 都在用户定义的暂停时间内连续工作以减少碎片。这超出了之前两种 GC 方式的能力。CMS(并发标记扫描)垃圾回收不会进行压缩。ParallelOld 垃圾收集仅执行整个堆压缩,这导致相当长的暂停时间。

G1 具有尝试达到的暂停时间目标(软实时)。在 Young GC 中,G1 会调整其 Young generation(Eden 和 Survivor),以达到软实时目标。在混合收集期间,G1 根据以下因素来调整对 Old 区域的收集数量:混合垃圾收集的目标数量、堆内每个区域活跃对象的百分比、总体可接受的堆浪费百分比。

G1 通过将活动对象从一个或多个区域集(称为集合集(CSet))增量并行复制到不同的新区域中来实现压缩,从而减少了堆碎片。目标是从包含最大可回收空间的那些区域开始,尽可能多地回收堆空间,同时尝试不超过暂停时间目标(garbage first)。

除了构成 stop-the-world 的 Young GC 和 Mixed GC 外,G1 还拥有并行、并发和多阶段标记周期。

Young GC: G1 会收集 Eden 及 Survivor 区域,从这些区域中存活下来的对象将被拷贝或疏散至新的区域。特定对象的目标区域取决于对象的年龄,年龄达到一定阈值的对象将被疏散到老年代(即被晋升),否则将被疏散至 Survivor 区域并将被包含在下一次 Young GC 或 Mixed GC 时的 CSet 中。

Mixed GC: 成功完成并发标记周期后,G1 从执行 Young GC 切换为执行 Mixed GC。在 Mixed GC 中,G1 选择性的添加一些老年代区域至 Eden 和 Survivor 组成的区域中以被收集。添加的老年的区域的数量由许多标志控制。在 G1 收集足够数量的老年代区域后(在多次 Mixed GC 后),G1 调整回执行 Young GC 直到下一次标记周期完成。

在 G1 中,任何大于区域大小一半的对象都被视为 Humongous Object,这样的对象直接分配到老年代的 “Humongous regions” 中。这些 “Humongous regions” 是一组连续的区域。

在分配任何 Humongous 区域之前,将检查标记阈值,并在必要时启动并发标记。

死亡的 Humongous Object 在标记周期的清理阶段或 Full GC 时被回收。

为了减少复制开销,任何疏散暂停中均不包括 Humongous Object。Full GC 将对 Humongous Object 进行压缩。

如果你看到连续的由 Humongous 申请触发的并发标记并且这些申请使你的老年代碎片化,请增大你的 -XX:G1HeapRegionSize 以使这些之前的 Humongous Object 不再被判定为 Humongous Object 以遵循常规的分配路径。

G1 的首要目标是为运行需要大堆且对 GC 延迟时间限制的应用程序的用户提供解决方案。这意味着堆大小约为 6GB 或更大,并且稳定且可预测的暂停时间低于 0.5 秒。

如果当前具有 CMS 或 ParallelOld 垃圾收集器运行的应用程序具有以下一个或多个特征,则将其切换到 G1 将非常有益。

  • 超过 50% 的 Java 堆被实时数据占用。
  • 对象分配率或提升率差异很大。
  • 不必要的长时间垃圾收集或压缩暂停(长于 0.5 到 1 秒)

G1 被规划作为并发标记扫描收集器(CMS)的长期替代产品。将 G1 与 CMS 进行比较,存在一些差异,这些差异使 G1 成为更好的解决方案。一个区别是 G1 是压缩收集器。G1 足够紧凑,可以完全避免使用细粒度的空闲列表进行分配,而是依赖于区域。这大大简化了收集器的各个部分,并消除了潜在的碎片问题。此外,G1 提供的垃圾收集暂停比 CMS 收集器更具可预测性,并允许用户指定所需的暂停目标。