46

有人可以解释一下 G1 垃圾收集器是如何工作的吗?我还没有在任何地方找到任何全面、易于理解的描述。

谢谢

4

3 回答 3

45

收集器将堆分成固定大小的区域并跟踪这些区域中的实时数据。它保留了一组指针——“记忆集”——进出该区域。当认为有必要进行 GC 时,它首先收集实时数据较少的区域(因此,“垃圾优先”)。通常,这可能意味着一步收集整个区域:如果指向某个区域的指针数量为零,则不需要对该区域进行标记或扫描。

对于每个区域,它会跟踪各种指标,这些指标描述了收集它们需要多长时间。您可以给它一个关于暂停时间的软实时约束,然后它会尝试在该受限时间内尽可能多地收集垃圾。

有 JavaOne 谈论 G1 和一些关于该主题的文章:

于 2010-05-21T12:46:36.473 回答
35

在这个新的 JavaOne 2012 会议中也很好地解释了 G1:G1 垃圾收集器性能调整 [ youtube ]、[ PDF ]。

他们首先介绍了 CMS 和 G1,它们的比较,然后解释了 G1 分析和调整。

G1特性

  • 固定大小区域- 堆拆分为区域(1Mb - 32MB,~2000,由 VM 确定)。
  • Eden、survivor 和 OldGen 表示为一组逻辑区域
  • 活体从一个区域疏散到另一个区域

典型的 G1 堆可能如下所示:

典型的 G1 堆可能如下所示:

以下是每个 G1 阶段的摘要:

1. 青年收藏

1.1年轻阶段——Minor GC

  • Evacuation - Stop-The-World 并行次要 GC,其中活动对象从年轻一代疏散到幸存者区域(tenuring)或 OldGen 区域(提升)。
  • 会计- 下一次年轻 GC 的伊甸园/幸存者空间的大小是根据每个区域的统计数据和应用程序设置的暂停时间目标确定的。G1 估计下一次 YoungGC 需要多少时间。
  • 调整大小- G1 现在可以轻松地减少/调整伊甸园/幸存者区域的大小。

1.2年轻/初始标记

  • GC young initial-mark是与 YoungGC 集合并行执行的 OldGen 集合的初始标记阶段。初始标记是一个并行并发标记过程。

2. 老一代收藏

2.1初始标记- 见 1.2。

2.2 GC备注

  • 一站式停顿,同时标记活动对象
  • 会计 - 对于每个区域,在备注期间,G1 正在跟踪该区域的活跃度(每个区域中有多少对象存在),以及对该区域的引用(Remembered Set) - 这告诉 G1 需要多长时间才能对此进行收集地区。
  • 回收的空白区域

2.3. GC 暂停(混合)

  • 选择活跃度低的地区并收集其中的一些。因此,我们正在收集“垃圾优先”。
  • 这些区域的实际收集是在下一次 Young GC 的同时执行的,因此没有单独的 OldGen 收集暂停。因此,GC pause(混合)是 YoungGen 和一部分 old Gen 的混合集合。
  • 在 GC 暂停(混合)结束时,旧代区域中可能会留下一些垃圾,稍后将根据未来的活跃度、暂停时间目标和未使用区域的数量来收集这些垃圾。

3.全GC

请注意,G1 旨在尽可能避免 Full GC。从 Java 7u40 开始,G1 中的 FullGC 暂停没有优化,而是作为单线程操作实现的。使用 G1 时,尽量避免 Full GC - 如果您看到任何 FullGC 暂停,您的 GC 设置可能需要一些调整。

资源

于 2013-10-10T18:33:40.170 回答
3

我发现Oracle在这方面的页面非常有助于以易于理解的方式解释这些概念,而且不会太冗长。

于 2018-01-19T22:39:43.380 回答