Java G1垃圾回收

G1 垃圾收集器

Garbage-First (G1) 收集器是一种服务器式垃圾收集器,针对具有大内存的多处理器机器。它以高概率满足垃圾收集 (GC) 暂停时间目标,同时实现高吞吐量。 Oracle JDK 7 update 4 及更高版本完全支持 G1 垃圾收集器。 G1 收集器专为以下应用而设计:

  • 可以与 CMS 收集器等应用程序线程同时操作。
  • 紧凑的可用空间,没有冗长的 GC 引起的暂停时间。
  • 需要更多可预测的 GC 暂停持续时间。
  • 不想牺牲很多吞吐量性能。
  • 不需要更大的 Java 堆。

    G1 计划作为 Concurrent Mark-Sweep Collector (CMS) 的长期替代品。将 G1 与 CMS 进行比较,G1 是一个更好的解决方案。一个区别是 G1 是一个压缩收集器。 G1 充分压缩以完全避免使用细粒度的空闲列表进行分配,而是依赖于区域。这大大简化了收集器的各个部分,并且主要消除了潜在的碎片问题。此外,G1 提供比 CMS 收集器更可预测的垃圾收集暂停,并允许用户指定所需的暂停目标。

G1运行概览

较旧的垃圾收集器(串行(serial)、并行(parallel)、CMS)都将堆分为三个部分:年轻代、老年代和固定内存大小的永久代。


所有内存对象最终都位于这三个部分之一中。

G1 收集器采用不同的方法。



堆被划分为一组大小相等的堆区域,每个区域都是连续的虚拟内存范围。某些区域集被分配了与旧收集器相同的角色(eden、survivor、old),但它们没有固定的大小。这为内存使用提供了更大的灵活性。

在执行垃圾回收时,G1 以类似于 CMS 回收器的方式运行。 G1 执行一个并发的全局标记阶段来确定整个堆中对象的活跃度。标记阶段完成后,G1 知道哪些区域大部分是空的。它首先在这些区域收集,这通常会产生大量的可用空间。这就是为什么这种垃圾收集方法被称为 Garbage-First 的原因。顾名思义,G1 将其收集和压缩活动集中在堆中可能充满可回收对象的区域,即垃圾。 G1 使用停顿预测模型来满足用户定义的停顿时间目标,并根据指定的停顿时间目标选择要收集的区域数。

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

需要注意的是,G1 不是实时收集器。它以高概率但不是绝对确定地满足设定的暂停时间目标。根据之前收集的数据,G1 会估计在用户指定的目标时间内可以收集多少个区域。因此,收集器有一个相当准确的区域收集成本模型,并且它使用该模型来确定要收集哪些区域以及要收集多少区域,同时保持在暂停时间目标内。

注意:G1 具有并发(与应用程序线程一起运行,例如,细化(refinement)、标记(marking)、清理(cleanup))和并行(多线程,例如,STW)阶段。Full GC仍然是单线程的,但如果调整得当,您的应用程序应该避免Full GC。

G1足迹

如果您从 ParallelOldGC 或 CMS 收集器迁移到 G1,您可能会看到更大的 JVM 进程大小。这主要与“记帐(accounting)”数据结构有关,例如记忆集(Remembered Sets)和集合集(Collection Sets)。

记忆集(Remembered Sets)或 RSets 将对象引用跟踪到给定区域。堆中的每个区域都有一个 RSet。RSet 支持区域的并行和独立收集。RSets 的总体足迹影响小于 5%。

Collection Sets 或 CSets 将在 GC 中收集的区域集。在 GC 期间,CSet 中的所有实时数据都会被撤出(复制/移动)。区域集可以是Eden、survivor 和/或 old generation。CSet 对 JVM 大小的影响不到 1%。

G1 的推荐用例

G1 的第一个重点是为运行需要大堆且 GC 延迟有限的应用程序的用户提供解决方案。这意味着大约 6GB 或更大的堆大小,以及低于 0.5 秒的稳定且可预测的暂停时间。

如果应用程序具有以下一个或多个特征,则现在使用 CMS 或 ParallelOldGC 垃圾收集器运行的应用程序将受益于切换到 G1。

  • Full GC 持续时间太长或太频繁。
  • 对象分配率或提升率差异很大。
  • 不需要的长时间垃圾收集或压缩暂停(超过 0.5 到 1 秒)

注意:如果您使用的是 CMS 或 ParallelOldGC,并且您的应用程序没有经历长时间的垃圾收集暂停,则可以继续使用当前的收集器。使用最新的 JDK 不需要更改为 G1 收集器。

使用 CMS 查看 GC

查看分代 GC 和 CMS

Concurrent Mark Sweep (CMS) 收集器(也称为并发低暂停收集器)收集老年代。它试图通过与应用程序线程同时进行大部分垃圾收集工作来最小化由于垃圾收集而导致的暂停。通常并发低暂停收集器不会复制或压缩活动对象。垃圾收集是在不移动活动对象的情况下完成的。如果碎片成为问题,请分配更大的堆。

注意:年轻代的 CMS 收集器使用与并行收集器相同的算法。

CMS 收集阶段

CMS 收集器在老年代堆上执行以下阶段:

阶段 描述
(1) 初始标记 STW 老一代中的对象被“标记”为可访问的,包括那些可以从年轻代访问的对象。与Minor收集暂停时间相比,暂停时间通常较短。
(2) 并发标记 在 Java 应用程序线程正在执行时,同时遍历可访问对象的永久生成对象图。从标记的对象开始扫描并传递标记从根可到达的所有对象。 mutator 在并发阶段 2、3 和 5 期间执行,并且在这些阶段期间在 CMS 生成中分配的任何对象(包括提升的对象)都会立即标记为活动的。
(3)重新标记 STW 在并发收集器完成跟踪该对象后,查找由于 Java 应用程序线程更新对象而被并发标记阶段遗漏的对象。
(4)并发清楚 在标记阶段收集标识为无法访问的对象。死对象的集合将对象的空间添加到空闲列表以供以后分配。此时可能会发生死对象的合并。请注意,活动对象不会移动。
(5) 复位 通过清除数据结构为下一次并发收集做准备。

查看垃圾收集步骤

接下来,让我们一步步回顾CMS Collector的操作。

  1. CMS 收集器的堆结构
    堆被分成三个空间。


年轻代分为Eden和两个survivor空间。老年代是一个连续的空间。对象收集就地完成。除非有Full GC,否则不会进行压缩。

  1. Young GC 在 CMS 中的工作原理
    新生代为浅绿色,老年代为蓝色。如果您的应用程序已经运行了一段时间,这就是 CMS 的样子。对象分散在老年代区域周围。


使用 CMS,老年代对象被原地释放。他们没有四处移动。除非有Full GC,否则不会压缩空间。

  1. 年轻一代合集
    活动对象从Eden空间和survivor空间复制到另一个survivor空间。任何达到其老化阈值的旧对象都会被提升为老年代。


  2. 在年轻 GC 之后
    在年轻 GC 之后,Eden 空间被清除,survivor空间之一被清除。


新提升的对象在图表上以深蓝色显示。绿色对象是尚未提升到老年代的幸存年轻代对象。

  1. 带有 CMS 的老一代集合
    两个STW事件发生:初始标记和备注。当老年代达到一定的占用率时,CMS就会启动。



    (1) 初始标记是一个短暂的暂停阶段,在此标记活动(可达)对象。(2) 并发标记在应用程序继续执行时发现活动对象。最后,在(3)重新标记阶段,发现在前一个阶段(2)并发标记期间遗漏的对象。

  2. 老年代收集 - 并发清除
    在前一阶段未标记的对象将被原地释放。没有压缩 。


注意:未标记的对象 == 死对象

  1. 老一代合集-清除后
    (4)清除阶段之后,可以看到已经释放了很多内存。您还会注意到没有进行任何压缩。


最后,CMS 收集器将通过 (5) 重置阶段并等待下一次达到 GC 阈值。

G1 垃圾收集器一步一步

G1 收集器采用不同的方法来分配堆。下面的图片逐步回顾了 G1 系统。

  1. G1 堆结构
    堆是一个内存区域,分为许多固定大小的区域。



    区域大小由 JVM 在启动时选择。 JVM 通常针对大约 2000 个区域,大小从 1 到 32Mb 不等。

  2. G1 堆分配
    实际上,这些区域被映射为 Eden、Survivor 和老年代空间的逻辑表示。


图片中的颜色显示了哪个区域与哪个角色相关联。活动对象从一个区域撤离(即复制或移动)到另一个区域。区域被设计为在停止或不停止所有其他应用程序线程的情况下并行收集。

如图所示,区域可以分配到 Eden、Survivor 和老年代区域。此外,还有第四类物体,称为巨大区域(Humongous regions)。这些区域旨在容纳标准区域大小的 50% 或更大的对象。它们被存储为一组连续的区域。最后一种类型的区域将是堆中未使用的区域。

注意:在撰写本文时,收集巨大对象尚未优化。因此,您应该避免创建这种大小的对象。

  1. G1 中的年轻代
    堆被分成大约 2000 个区域。最小大小为 1Mb,最大大小为 32Mb。蓝色区域保存老年代对象,绿色区域保存年轻代对象。


请注意,这些区域不需要像旧的垃圾收集器那样是连续的。

  1. G1 中的Young GC
    活动对象被疏散(即复制或移动)到一个或多个幸存者区域。如果满足老化阈值,则将一些对象提升到老年代区域。


这是一个STW的暂停。为下一次Young GC 计算 Eden 大小和Survivor 大小。保留会计信息以帮助计算大小。考虑到暂停时间目标之类的事情。

  1. 使用 G1 结束 Young GC
    活动对象已被疏散到Survivor区域或老年代区域。


最近提升的对象以深蓝色显示。绿色的Survivor区域。

综上所述,G1中的年轻代可以这么说:

  • 堆是分割成多个区域的单个内存空间。
  • 年轻代内存由一组不连续的区域组成。这使得在需要时可以轻松调整大小。
  • 年轻代垃圾回收或Young GC 是STW事件。所有应用程序线程都为该操作停止。
  • Young GC 使用多个线程并行完成。
  • 活动对象被复制到新的Survivor或老年代区域。

带有 G1 的老年代集合

与 CMS 收集器一样,G1 收集器被设计为老年代对象的低暂停收集器。下表描述了老年代的 G1 收集阶段。

G1 收集阶段 - 并发标记周期阶段

G1 收集器在堆的老年代执行以下阶段。请注意,某些阶段是年轻代集合的一部分。

阶段 描述
(1) 初始标记 这是一个STW事件。使用 G1,它搭载在正常的Young GC 上。标记可能引用老年代对象的Survivor区域(根区域)。
(2) 根区域扫描 扫描Survivor区域以获取对老年代的引用。这会在应用程序继续运行时发生。该阶段必须在Young GC 发生之前完成。
(3) 并发标记 在整个堆上查找活动对象。这发生在应用程序运行时。这个阶段可以被年轻代垃圾回收打断。
(4) 重新标记 (STW) 完成堆中活动对象的标记。使用一种称为开始时快照 (SATB) 的算法,该算法比 CMS 收集器中使用的算法快得多。
(5) 清除 (STW和并发) 1. 对活动对象和完全自由的区域执行记帐(accounting)。 (STW)2. 清除记忆的集合。 (STW)3. 重置空白区域并将它们返回到空闲列表。 (并发)
(*) 复制 (STW) 这些是STW以将活动对象撤离或复制到新的未使用区域的停止。这可以通过记录为 [GC pause (young)] 的年轻代区域来完成。或者记录为 [GC Pause (mixed)] 的年轻代和老年代区域。

G1老年代收集一步一步

定义完阶段后,让我们看看它们如何与 G1 收集器中的老年代交互。

  1. 初始标记阶段
    活动对象的初始标记搭载在年轻代垃圾收集上。在日志中,这被标记为 GC pause (young)(initial-mark)。


  2. 并发标记阶段
    如果找到空区域(如“X”所示),它们会在重新标记阶段立即删除。此外,计算确定活跃度的“记账(accounting)”信息。


  3. 重新标记阶段
    空区域被移除并回收。现在计算所有区域的区域活跃度。


  4. 复制/清理阶段
    G1 选择“活跃度”最低的区域,即可以最快收集到的区域。然后这些区域会在Young GC 的同时被收集。这在日志中表示为 [GC pause (mixed)]。所以年轻一代和老一代同时被收集。


  5. 复制/清理阶段之后
    所选区域已被收集并压缩为图中所示的深蓝色区域和深绿色区域。


老年代GC总结

综上所述,关于老年代的 G1 垃圾回收,我们可以提出几个关键点。

  • 并发标记阶段
  1. 在应用程序运行时同时计算活跃度信息。
  2. 该活跃度信息确定了在撤离暂停期间哪些区域最适合回收。
  3. 没有像 CMS 那样的清扫阶段。
  • 重新标记阶段
  1. 使用 Snapshot-at-the-Beginning (SATB) 算法,该算法比 CMS 使用的要快得多。
  2. 完全空的区域被回收。
  • 复制/清理阶段
  1. 年轻代和老年代同时回收。
  2. 老年代区域是根据它们的活跃度来选择的。

命令行选项和最佳实践

在本节中,让我们看一下 G1 的各种命令行选项。

基本命令行

要启用 G1 收集器,请使用:-XX:+UseG1GC

以下是用于启动 JDK 演示和示例下载中包含的 Java2Demo 的示例命令行:
java -Xmx50m -Xms50m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar c:\javademos\demo\jfc\Java2D\Java2demo.jar

关键命令行开关

-XX:+UseG1GC - 告诉 JVM 使用 G1 垃圾收集器。

-XX:MaxGCPauseMillis=200 - 设置最大 GC 暂停时间的目标。这是一个软目标,JVM 将尽最大努力实现它。因此,暂停时间目标有时无法实现。默认值为 200 毫秒。

-XX:InitiatingHeapOccupancyPercent=45 - 启动并发 GC 周期的(整个)堆占用百分比。 G1 使用它来触发基于整个堆的占用情况的并发 GC 周期,而不仅仅是一代。值 0 表示“执行恒定的 GC 循环”。默认值为 45(即 45% 已满或已占用)。

最佳实践

在使用 G1 时,您应该遵循一些最佳实践。

不要设置年轻代大小

通过 -Xmn 显式设置年轻代大小会影响 G1 收集器的默认行为。

  • G1 将不再遵守集合的暂停时间目标。所以本质上,设置年轻代大小会禁用暂停时间目标。
  • G1 不再能够根据需要扩展和收缩年轻代空间。由于大小是固定的,因此无法更改大小。

响应时间指标

不要使用平均响应时间 (ART) 作为设置 XX:MaxGCPauseMillis= 的指标,而是考虑设置将在 90% 或更多时间内满足目标的值。这意味着 90% 的发出请求的用户不会遇到高于目标的响应时间。请记住,暂停时间是一个目标,不能保证总是能达到。

什么是疏散失败?

当 JVM 在 GC 期间为幸存者和提升对象用完堆区域时发生提升失败。堆无法扩展,因为它已经达到最大值。这在使用 -XX:+PrintGCDetails 时通过 to-space 溢出在 GC 日志中指示。这很贵!

  • GC 仍然必须继续,因此必须释放空间。
  • 未成功复制的对象必须在适当的位置进行永久保存。
  • 必须重新生成对 CSet 中区域 RSet 的任何更新。
  • 所有这些步骤都是昂贵的。

如何避免疏散失败

为避免疏散失败,请考虑以下选项。

  • 增加堆大小
  1. 增加-XX:G1ReservePercent=n,默认为10。
  2. G1 通过尝试让保留内存空闲以防需要更多“to-space”来创建假天花板。
  • 提前开始标记周期
  • 使用 -XX:ConcGCThreads=n 选项增加标记线程的数量。

G1 GC 开关的完整列表

这是 G1 GC 开关的完整列表。请记住使用上述最佳实践。

选项和默认值 描述
-XX:+UseG1GC 使用垃圾优先 (G1) 收集器
-XX:MaxGCPauseMillis=n 设置最大 GC 暂停时间的目标。这是一个软目标,JVM 将尽最大努力实现它。
-XX:InitiatingHeapOccupancyPercent=n 启动并发 GC 周期的(整个)堆占用百分比。它被 GC 使用,这些 GC 根据整个堆的占用情况触发并发 GC 周期,而不仅仅是一代(例如 G1)。值 0 表示“执行恒定的 GC 循环”。默认值为 45。
-XX:NewRatio=n 新/旧代大小的比率。默认值为 2。
-XX:SurvivorRatio=n Eden/Survivor空间大小的比率。默认值为 8。
-XX:MaxTenuringThreshold=n 任期阈值的最大值。默认值为 15。
-XX:ParallelGCThreads=n 设置在垃圾收集器的并行阶段使用的线程数。默认值随运行 JVM 的平台而异。
-XX:ConcGCThreads=n 并发垃圾收集器将使用的线程数。默认值随运行 JVM 的平台而异。
-XX:G1ReservePercent=n 将保留的堆数量设置为错误上限,以减少升级失败的可能性。默认值为 10。
-XX:G1HeapRegionSize=n 在 G1 中,Java 堆被细分为大小一致的区域。这设置了各个细分的大小。此参数的默认值是根据堆大小以符合人体工程学的方式确定的。最小值为 1Mb,最大值为 32Mb。

使用 G1 记录 GC

我们需要讨论的最后一个主题是使用日志信息来分析 G1 收集器的性能。本节简要概述了可用于收集数据的开关以及打印在日志中的信息。

设置日志详细信息

您可以将详细信息设置为三个不同的详细信息级别。

(1) -verbosegc(相当于-XX:+PrintGC)将日志的详细级别设置为fine。
样本输出

[GC pause (G1 Humongous Allocation) (young) (initial-mark) 24M- >21M(64M), 0.2349730 secs]
[GC pause (G1 Evacuation Pause) (mixed) 66M->21M(236M), 0.1625268 secs] 

(2) -XX:+PrintGCDetails 设置细节级别finer。选项显示以下信息:

  • 显示每个阶段的平均、最小和最大时间。
  • 根扫描、RSet 更新(带有已处理的缓冲区信息)、RSet 扫描、对象复制、终止(带有尝试次数)。
  • 还显示“其他”时间,例如选择 CSet、引用处理、引用入队和释放 CSet 所花费的时间。
  • 显示 Eden、Survivors 和 Total Heap 占用。

样本输出

[Ext Root Scanning (ms): Avg: 1.7 Min: 0.0 Max: 3.7 Diff: 3.7]
[Eden: 818M(818M)->0B(714M) Survivors: 0B->104M Heap: 836M(4096M)->409M(4096M)]

(3) -XX:+UnlockExperimentalVMOptions -XX:G1LogLevel=finest 将细节级别设置为finest。像finer,但包括单独的工作线程信息。

[Ext Root Scanning (ms): 2.1 2.4 2.0 0.0
           Avg: 1.6 Min: 0.0 Max: 2.4 Diff: 2.3]
       [Update RS (ms):  0.4  0.2  0.4  0.0
           Avg: 0.2 Min: 0.0 Max: 0.4 Diff: 0.4]
           [Processed Buffers : 5 1 10 0
           Sum: 16, Avg: 4, Min: 0, Max: 10, Diff: 10]

确定时间

几个开关决定了时间在 GC 日志中的显示方式。
(1) -XX:+PrintGCTimeStamps - 显示自 JVM 启动以来经过的时间。
样本输出

    1.729: [GC pause (young) 46M->35M(1332M), 0.0310029 secs]

(2) -XX:+PrintGCDateStamps - 为每个条目添加时间前缀。

    2012-05-02T11:16:32.057+0200: [GC pause (young) 46M->35M(1332M), 0.0317225 secs]

了解 G1 日志

为了理解日志,本节定义了一些使用实际 GC 日志输出的术语。以下示例显示了日志的输出以及您将在其中找到的术语和值的解释。

G1 记录术语索引

Clear CT
CSet
External Root Scanning
Free CSet
GC Worker End
GC Worker Other
Object Copy
Other
Parallel Time
Ref Eng
Ref Proc
Scanning Remembered Sets
Termination Time
Update Remembered Set
Worker Start

Parallel Time

414.557: [GC pause (young), 0.03039600 secs] [Parallel Time: 22.9 ms]
[GC Worker Start (ms): 7096.0 7096.0 7096.1 7096.1 706.1 7096.1 7096.1 7096.1 7096.2 7096.2 7096.2 7096.2
       Avg: 7096.1, Min: 7096.0, Max: 7096.2, Diff: 0.2]

Parallel Time – 暂停的主要并行部分的总经过时间
Worker Start – 工作开始的时间戳
注意:日志按线程 id 排序,并且在每个条目上都是一致的

External Root Scanning

[Ext Root Scanning (ms): 3.1 3.4 3.4 3.0 4.2 2.0 3.6 3.2 3.4 7.7 3.7 4.4
     Avg: 3.8, Min: 2.0, Max: 7.7, Diff: 5.7]

External root scanning - 扫描外部根所花费的时间(例如,指向堆的系统字典之类的东西。)

Update Remembered Set

[Update RS (ms): 0.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 Avg: 0.0, Min: 0.0, Max: 0.1, Diff: 0.1]
   [Processed Buffers : 26 0 0 0 0 0 0 0 0 0 0 0
    Sum: 26, Avg: 2, Min: 0, Max: 26, Diff: 26]
Update Remembered Set - 必须更新在暂停开始之前已完成但尚未由并发细化线程处理的任何缓冲区。时间取决于卡片的密度。卡越多,需要的时间就越长。

Scanning Remembered Sets

[Scan RS (ms): 0.4 0.2 0.1 0.3 0.0 0.0 0.1 0.2 0.0 0.1 0.0 0.0 Avg: 0.1, Min: 0.0, Max: 0.4, Diff: 0.3]F

Scanning Remembered Sets - 寻找指向集合集的指针。

Object Copy

[Object Copy (ms): 16.7 16.7 16.7 16.9 16.0 18.1 16.5 16.8 16.7 12.3 16.4 15.7 Avg: 16.3, Min: 12.3, Max:  18.1, Diff: 5.8]
Object copy – 每个单独线程花费在复制和撤离对象的时间。

Termination Time

[Termination (ms): 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 Avg: 0.0, Min: 0.0, Max: 0.0, Diff: 0.0] [Termination Attempts : 1 1 1 1 1 1 1 1 1 1 1 1 Sum: 12, Avg: 1, Min: 1, Max: 1, Diff: 0]

Termination time - 当工作线程完成其要复制和扫描的特定对象集时,它进入终止协议。它寻找要窃取的工作,一旦完成该工作,它就会再次进入终止协议。终止尝试计算所有窃取工作的尝试。

GC Worker End

[GC Worker End (ms): 7116.4 7116.3 7116.4 7116.3 7116.4 7116.3 7116.4 7116.4 7116.4 7116.4 7116.3 7116.3
    Avg: 7116.4, Min: 7116.3, Max: 7116.4, Diff:   0.1]
[GC Worker (ms): 20.4 20.3 20.3 20.2 20.3 20.2 20.2 20.2 20.3 20.2 20.1 20.1
     Avg: 20.2, Min: 20.1, Max: 20.4, Diff: 0.3]

GC worker end time – 单个 GC 工作停止时的时间戳。
GC worker time – 单个 GC 工作线程花费的时间。

GC Worker Other

[GC Worker Other (ms): 2.6 2.6 2.7 2.7 2.7 2.7 2.7 2.8 2.8 2.8 2.8 2.8
    Avg: 2.7, Min: 2.6, Max: 2.8, Diff: 0.2]

GC worker other – 不能归因于前面列出的工作阶段的时间(对于每个 GC 线程)。应该很低。过去,我们看到过高的值,它们被归因于 JVM 其他部分的瓶颈(例如,分层代码缓存占用率增加)。

Clear CT

[Clear CT: 0.6 ms]

清除RSet扫描元数据卡表所用时间

Other

[Other: 6.8 ms]

GC 暂停的各种其他顺序阶段所花费的时间。

CSet

[Choose CSet: 0.1 ms]

最终确定要收集的区域集所花费的时间。通常非常小;必须选择旧时稍长。

Ref Proc

[Ref Proc: 4.4 ms]

处理从 GC 的先前阶段推迟的软、弱等引用所花费的时间。

Ref Enq

[Ref Enq: 0.1 ms]

将软、弱等引用放入待处理列表所花费的时间。

Free CSet

[Free CSet: 2.0 ms]

释放刚刚收集的区域集(包括它们的记忆集)所花费的时间。

总结

在本 OBE 中,您将了解 Java JVM 中包含的 G1 垃圾收集器的概述。首先,您了解了堆和垃圾收集器如何成为任何 Java JVM 的关键部分。接下来你回顾了垃圾收集是如何使用 CMS 收集器和 G1 收集器工作的。接下来,您了解了 G1 命令行开关以及使用它们的最佳实践。最后,您了解了 GC 日志中包含的日志记录对象和数据。

在本教程中,您学习了:

  • Java JVM 的组件
  • G1 收集器概述
  • CMS 收集器的回顾
  • G1 收集器的查看
  • 命令行开关和最佳实践
  • 使用 G1 日志

你可能感兴趣的:(Java G1垃圾回收)