G1垃圾收集器入门

G1垃圾收集器入门

原文网站

概述

目的

这篇文章涵盖了G1垃圾收集器的基本用法以及它被用于HotspotJVM的方式。您将了解G1收集器的内部工作原理、使用G1的关键命令行开关以及记录其操作的选项。

阅读时长

接近一小时

简介

这篇文档介绍了Java虚拟机(JVM)G1垃圾收集(GC)的基本知识。在本文的第一部分是对JVM伴随垃圾回收器性能的概述。接下来我们回顾CMS收集器如何与hotspotJVM协同工作。然后,我们通过HotspotJVM上的G1垃圾收集器逐步介绍垃圾收集器的工作原理。在接下来的一个部分,介绍G1垃圾收集器中可用的垃圾收集命令行选项。最后,您将了解与G1收集器一起使用的日志记录选项。

软硬件需求

以下是硬件和软件要求列表:

  • 需要在Windows XP或更高版本的PC上运行。请注意,实际操作是在Windows7上完成的,但是并没有在所有平台上进行测试。不过,在OSX或Linux上一切都应该可以正常工作。此外,最好使用至少一个机芯。
  • Java 7 Update 9 or later
  • 最新的Java7演示和示例Zip文件

先决条件

在开始本教程之前,您应该:

  • 如果您还没有这样做,请下载并安装最新版本的javajdk(jdk7u9或更高版本)。
    Java 7 JDK Downloads
  • 从相同的位置下载和安装示例。解压缩文件并将内容放入目录中。例如:C:\javademos

Java技术与JVM

Java概述

Java概述

Java是sunmicrosystems于1995年首次发布的一种编程语言和计算平台。它是驱动Java程序(包括实用程序、游戏和业务应用程序)的底层技术。Java在全球超过8.5亿台个人电脑上运行,在全球数十亿台设备上运行,包括移动设备和电视设备。Java是由许多关键组件组成的,这些组件作为一个整体,创建了Java平台。

Java运行时版

下载Java时,您将获得Java运行时环境(JRE)。JRE由Java虚拟机(JVM)、Java平台核心类和支持Java平台库组成。在您的计算机上运行Java应用程序需要这三种方法。在Java7中,Java应用程序从操作系统作为桌面应用程序运行,作为桌面应用程序但使用Java Web Start从Web安装,或作为浏览器中的Web嵌入式应用程序(使用JavaFX)运行。

Java编程语言

Java是一种面向对象的编程语言,它包括以下特性。

  • 平台独立性——Java应用程序被编译成字节码,字节码存储在类文件中并加载到JVM中。由于应用程序在JVM中运行,所以它们可以在许多不同的操作系统和设备上运行。
  • 面向对象——java是一种面向对象语言,它具有C++和C++的许多特性并改进了它们。
  • 自动垃圾收集——Java自动分配和释放内存,这样程序就不必处理这个任务。
  • 丰富的标准库—— Java包含大量可用于执行输入/输出、联网和日期操作等任务的预制对象。

Java开发工具包

java开发工具包(JDK)是用于开发Java应用程序的工具集合。使用JDK,您可以编译用Java编程语言编写的程序,并在JVM中运行它们。此外,JDK还提供了打包和分发应用程序的工具。

JDK和JRE共享Java应用程序编程接口(javaapi). javaapi是开发人员用来创建Java应用程序的预打包库的集合。javaapi通过提供工具来完成许多常见的编程任务,包括字符串操作、日期/时间处理、联网和实现数据结构(例如,列表、映射、堆栈和队列),使开发变得更加容易。

Java 虚拟机(JVM)

Java虚拟机(JVM)是一种抽象计算机器。JVM是一个程序,对于编写在其中执行的程序来说,它看起来像一台机器。这样,Java程序就被写入同一组接口和库中。针对特定操作系统的每个JVM实现都将Java编程指令转换为在本地操作系统上运行的指令和命令。这样,Java程序就实现了平台独立性。

第一个Java虚拟机的原型实现是由Sun Microsystems, Inc.完成的,它模拟了Java虚拟机指令集,该软件由一个类似于当代个人数字助理(PDA)的手持设备托管。Oracle当前的实现在移动设备、桌面设备和服务器设备上模拟Java虚拟机,但Java虚拟机不采用任何特定的实现技术、主机硬件或主机操作系统。它不是固有的解释,但也可以通过编译其指令集为硅CPU来实现。它也可以在微码或直接在硅中实现。

Java虚拟机对Java编程语言一无所知,只知道一种特殊的二进制格式,类文件格式。类文件包含Java虚拟机指令(字节码)和符号表以及其他辅助信息。

为了安全起见,Java虚拟机对类文件中的代码施加了强大的语法和结构约束。然而,任何具有可用有效类文件表示的功能的语言都可以由Java虚拟机托管。被一个普遍可用的、独立于机器的平台所吸引,其他语言的实现者可以将Java虚拟机作为其语言的传递工具。

探索JVM架构

Hotspot 架构

jvm_Architecture.PNG

JVM的主要组件包括类加载器、运行时数据区域和执行引擎。

Key Hotspot Components

JVM中与性能相关的关键组件在下图中高亮显示。

key_hotspot_jvm_components

在优化性能时,JVM有三个组件是重点关注的。是存储对象数据的地方,该区域由启动时选择的垃圾回收器管理。大多数优化选项都与调整堆大小和为您的情况选择最合适的垃圾收集器有关。JIT编译器对性能也有很大的影响,但很少需要对JVM的较新版本进行调优。

性能基础

通常,在调优Java应用程序时,重点放在两个主要目标之一:响应性或吞吐量。随着教程的进展,我们将回顾这些概念。

响应性

响应性是指应用程序或系统对请求的数据段作出响应的速度。示例包括:

  • 桌面UI响应事件的速度
  • 网站返回页面的速度的快慢
  • 数据库查询返回的速度

For applications that focus on responsiveness, large pause times are not acceptable. The focus is on responding in short periods of time.

对于专注于响应性的应用程序,比较长的停顿时间是不可接受的。重点是在短时间内做出反应。

吞吐量

吞吐量的重点是在特定时间段内使应用程序的工作量最大化。衡量吞吐量的示例包括:

  • 在给定时间内完成的事务数。
  • 批处理程序在一小时内可以完成的作业数。
  • 一小时内可以完成的数据库查询数。

对于关注吞吐量的应用程序来说,高暂停时间是可以接受的。由于高吞吐量应用程序关注的是较长时间内的基准测试,因此不考虑快速响应时间。

G1 垃圾收集器

G1 垃圾收集器

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

  • 像CMS收集器一样可以和应用程序并发运行。
  • 压缩空闲的空间无需漫长的停顿时间。
  • 更需要可预测的GC暂停持续时间。
  • 不想牺牲很多吞吐量性能。
  • 不需要更大的Java堆。

G1致力于并行标记扫描采集器(CMS)的长期替代品。G1相比于CMS垃圾收集器,最大区别是G1具有更好的解决方案。一个区别是G1是一个可压缩收集器。G1进行了充分的压缩,以完全避免使用细粒度的自由列表进行分配,而是依赖于区域。这大大简化了收集器的各个部分,并且基本上消除了潜在的碎片问题。此外,G1提供了比CMS收集器更可预测的垃圾收集暂停,并允许用户指定所需的暂停目标。

G1 操作概述

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

HeapStructure

所有的内存对象都在这三个部分中的一个。

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

g1_heap_allocation

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

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

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

需要注意的是,G1不是实时收集器。它很有可能达到设定的暂停时间目标,但不是绝对确定的。根据一个用户在一个目标区域内收集到多少个数据,可以根据指定的时间段内收集多少个数据。因此,收集器有一个相当精确的区域收集成本模型,它使用该模型来确定在暂停时间目标内要收集哪些区域以及收集多少区域。

Note: G1既有并发(与应用程序线程一起运行,例如,细化、标记、清理)和并行(多线程,例如stop the world)阶段。完整的垃圾收集仍然是单线程的,但是如果调整得当,您的应用程序应该避免使用完整的gc。

G1 Footprint

如果从parallelloldgc或CMS收集器迁移到G1,您可能会看到更大的JVM进程大小。这在很大程度上与“会计”数据结构(如记忆集和收集集)有关。

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

集合集或CSets将在GC中收集的区域集。在GC期间,CSet中的所有实时数据都会被清空(复制/移动)。区域集可以是伊甸园、幸存者和或者老年代。CSets对JVM大小的影响不到1%。

G1的推荐用例

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

如果应用程序具有以下一个或多个特征,那么使用CMS或parallelloldgc垃圾回收器运行的应用程序将有助于切换到G1。

  • 完整的GC持续时间太长或太频繁。
  • 对象分配率或提升率差异显著。
  • 意外的长时间垃圾收集或压缩暂停(超过0.5到1秒)

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

回顾常用的垃圾收集器和CMS

回顾常用的垃圾收集器和CMS

并发标记-清除(CMS)收集器(也称为并发低暂停收集器)收集持久代。它试图通过与应用程序线程同时执行大部分垃圾回收工作来尽量减少由于垃圾回收而导致的暂停。通常并发低暂停收集器不会复制或压缩活动对象。垃圾收集是在不移动活动对象的情况下完成的。如果碎片化成为一个问题,分配一个更大的堆。

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

CMS收集阶段

CMS收集器对旧一代堆执行以下阶段:

PhaseDescription
(1) 初识标记 (STW )老一代中的对象被“标记”为可到达的,包括那些从年轻一代可以到达的对象。与次要收集暂停时间相比,暂停时间通常较短。
(2) 并发标记在执行Java应用程序线程时,同时遍历可访问对象的保留生成对象图。从标记的对象开始扫描,并传递性地标记所有可从根访问的对象。在并发阶段2、3和5中执行赋值函数,并且在这些阶段中分配给CMS生成的任何对象(包括提升的对象)都会立即标记为活动的。
(3) 标记 (STW)查找由于并发收集器完成跟踪对象后Java应用程序线程对对象的更新而在并发标记阶段丢失的对象。
(4) 并发清除收集在标记阶段标识为不可访问的对象。死对象的集合会将对象的空间添加到空闲列表中,以便以后分配。在这一点上,死物体可能会合并。请注意,活动对象不会被移动。
(5) 重设阶段通过清除数据结构为下一次并发收集做好准备。

查看垃圾收集步骤

接下来,让我们一步一步地回顾CMS收集器的操作。

1.CMS收集器的堆结构

堆被分成三个空间。

cms_heap_structure
年轻代被分成伊甸园和两个幸存者空间。老年代是一个连续的空间。对象收集已完成。除非有完整的GC,否则不进行压实。

2.年轻代GC如何在CMS中工作

年轻代是浅绿色的,老年代是蓝色的。如果你的应用程序已经运行了一段时间,这就是CMS的样子。对象散落在老年代区域。

how_young_gc_works
使用CMS,老年代对象被释放到适当的位置。它们不会被移动。除非有完整的GC,否则空间不会被压缩。

3. 年轻代收集

存活对象从Eden空间和幸存者空间复制到另一个幸存者空间。任何已达到老年代阈值的旧对象都将升级到老年代。

young_generation_collection
4. Young GC之后

在Young GC过后,Eden区域和一个survivor区域被清除。

after_young_gc
新升级的对象在图表上以深蓝色显示。绿色对象是尚未被提升到老年代的幸存的年轻代对象。
5. CMS收集老年代
两个STW事件发生:初始标记和标记阶段。当老年代达到一定比率时,启动CMS。
old_gen_collection_in_cms
(1) 初始标记是标记活动(可到达)对象的短暂暂停阶段。(2) 并发标记在应用程序继续执行时查找活动对象。最后,在(3)备注阶段,发现前一阶段(2)并发标记过程中遗漏的对象。

6. 老年代收集-并行扫描

上一阶段未标记的对象将就地释放。没有压缩。
old_gen_collection_concurrent_sweep
Note: 未标记的对象就等于死对象

7. 老年代收集器 - 事后清除

在(4)扫描阶段之后,您可以看到大量内存被释放。您还将注意到没有进行压缩。

old_gen_collection_after_sweeping

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

逐步分析G1垃圾收集器

逐步分析G1垃圾收集器

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

1. G1堆结构

堆是一个内存区域,分成许多固定大小的区域。.

g1_heap_structure

区域大小由JVM在启动时选择。JVM的目标大小通常设置2000个区域,每个区域为1到32MB。

2. G1堆分配

在实际过程中,这个区域映射到逻辑形式展现的Eden、Survivor区域和老年代区域。

g1_heap_allocation

图片中的颜色显示了哪个区域与哪个角色相关联。存活对象从一个区域疏散到另一个区域(即复制或移动)。区域被设计成与所有其他应用程序线程并行收集,也可以不停止所有其他应用程序线程。

如图所示,区域可以被分配到伊甸园、幸存者和老年代区域。此外,还有第四种类型的对象被称为巨大的区域。这些区域被设计用来容纳大小为标准区域50%或更大的对象。它们存储为一组连续的区域。最后一种类型的区域是堆中未使用的区域。

Note: 在写这篇文章的时候,收集巨大的对象还没有得到优化。因此,应该避免创建这种大小的对象。

3. G1眼中的年轻代

堆被分成大约2000个区域。最小大小为1Mb,最大大小为32Mb。蓝色区域包含老年代对象,绿色区域包含年轻代对象。

young_generation_in_g1

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

4. A G1眼中的Young GC

存活对象被疏散(即复制或移动)到一个或多个幸存者区域。如果满足老年代阈值,则某些对象将升级到老年代区域。

a_young_gc_in_g1

这是一个(STW)暂停。计算下一个年轻GC的Eden大小和幸存者大小。会计信息被保存以帮助计算大小。像暂停时间目标这样的事情也被考虑在内。

这种方法可以很容易地调整区域的大小,根据需要使它们变大或变小。

5. G1眼中的young GC结尾

存活对象被疏散到幸存者区或老一代地区。

end_of_young_gc_with_g1

最近升级的对象以深蓝色显示。幸存者区域为绿色。

综上所述,关于G1的年轻代可以这样说:

  • 堆是一个被分割成多个区域的单个内存空间。

  • 年轻代内存是由一组非连续区域组成的。这使得在需要时可以很容易地调整大小。

  • 年轻代的垃圾收集,或young gc,是STW的事件,该操作将停止所有应用程序线程。

  • 年轻的GC是使用多个线程并行完成的。

  • 存活对象被复制到新的幸存者或旧一代区域。

G1眼中的老年代收集

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

G1采集阶段-并行标记周期阶段

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

PhaseDescription
(1) 初识标记(STW)这是一个STW事件。在G1中,它搭载在一个正常的年轻GC上。标记幸存者区域(根区域),这些区域可能引用老年代中的对象。
(2) 根节点扫描扫描幸存者区域,寻找老年代的参考。当应用程序继续运行时会发生这种情况。该阶段必须在年轻GC出现之前完成。
(3) 并发标记在整个堆上查找存活对象。这是在应用程序运行时发生的。年轻代垃圾回收可以中断此阶段。
(4) 重新标记(STW)完成堆中活动对象的标记。使用一种称为“开始时快照”(SATB)的算法,该算法比CMS收集器中使用的算法快得多。
(5) 清除(STW 和并发)*对活动对象和完全自由区域执行记帐。(停止世界)清理记忆中的场景。(停止世界)重置空白区域并将其返回到空闲列表。(并行)
(6) 复制(STW)这些是停止世界暂停以疏散或复制活动对象到新的未使用区域。这可以通过记录为“[GC pause(young)]”的年轻代区域来实现。或同时记录为“[GC Pause(mixed)]”的年轻代和老一代区域。

G1 逐步分析老年代收集器

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

6.初识标记

存活对象的初始标记是在年轻代垃圾收集上进行的。在日志中,这被记为 GC pause (young)(inital-mark).

initial_marking_phase

7. 并发标记阶段

如果发现空区域(用“X”表示),则在备注阶段立即将其删除。此外,还计算了决定活跃度的“会计”信息。

concurrent_marking_phase

8. 标记阶段

删除并回收空区域。现在将计算所有区域的区域活动度。

remark_phase

9. 复制/清理阶段

G1选择“活跃度”最低的区域,也就是可以收集最快的区域。然后这些区域在年轻GC的同时被收集。这在日志中表示为“[GC pause(mixed)]”。所以年轻代和老年代同时被收集。

copying_cleanup_phase

10. 复制/清理阶段后

所选区域已被收集并压缩为图中所示的深蓝色区域和深绿色区域。

after_copying_cleanup_phase

老年代收集器综述

总之,对于老一代的G1垃圾回收,我们可以提出几个关键点。

  • 并发标记阶段

  • 在应用程序运行时并发计算活动信息。

  • 此活动信息确定在疏散暂停期间,哪些区域最适合回收。

  • 像CMS一样并没有清除阶段。

  • 重新标记阶段

  • 使用快照开始(SATB)算法,比CMS使用的算法快得多。

  • 完全空的区域被回收。

  • 复制/清理阶段

    • 年轻代和老年代同时再生。

    • 老年代区域根据其活跃程度进行选择。

命令行选项和最佳实践

命令行选项和最佳实践

在本节中,让我们看看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表示“do constant GC cycles”。默认值为45%(即45%已满或已占用)。

最佳实践

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

不要设定年轻代的大小

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

  • G1将不再考虑集合的暂停时间目标。因此,从本质上讲,设置年轻代的规模会禁用暂停时间目标。
  • G1已经无法根据需要扩大和收缩年轻代的空间。由于大小是固定的,因此无法更改大小。

响应时间指标

不要将平均响应时间(ART)用作设置XX:MaxGCPausEmilis=<N>’的度量,而应考虑设置将满足90%或更多时间目标的值。这意味着90%的用户提出请求不会经历比目标更高的响应时间。记住,暂停时间是一个目标,不一定总是被满足的。

什么是疏散失败?

在GC期间,对于幸存者和提升对象,当JVM用完堆区域时发生的提升失败。堆无法扩展,因为它已达到最大值。在使用“-XX:+PrintGCDetailsby**到空间溢出`**”时,GC日志中会指出这一点。代价太昂贵了!

  • GC仍然需要继续,因此必须释放空间。
  • 复制失败的对象必须保留在原位。
  • 对CSet中区域资源集的任何更新都必须重新生成。
  • 所有这些步骤都很昂贵。

如何避免疏散失败

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

  • 增加堆大小

    • 增加**-XX:G1ReservePercent=n**,默认值为10。

    • G1试图让保留内存空闲以防需要更多的“空间”,从而创建了一个假上限。

  • 提前开始标记循环

  • 使用**-XX:congcthreads=n**选项增加标记线程的数量。

G1垃圾收集器的完整列表

这是G1垃圾收集器开关的完整列表。记住使用上面列出的最佳实践。

Option and Default ValueDescription
-XX:+UseG1GC使用垃圾优先(G1)收集器
-XX:MaxGCPauseMillis=n设置最大GC暂停时间的目标。这是一个软目标,JVM将尽力实现它。
-XX:InitiatingHeapOccupancyPercent=n启动并发GC循环的(整个)堆占用率的百分比。它不是基于GCs的一个并发循环,而是基于GCs的一个并发循环。值为0表示“do constant GC cycles”。默认值为45。
-XX:NewRatio=n新老年代规模之比。默认值为2。
-XX:SurvivorRatio=n伊甸园/幸存者空间大小的比率。默认值为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的垃圾回收器的日志记录

关于G1的垃圾回收器的日志记录

我们需要讨论的最后一个主题是使用日志信息来分析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 将详细程度设置为精细。选项显示以下信息:

  • 将显示每个阶段的平均时间、最小时间和最大时间。
  • 根扫描、资源集更新(使用已处理的缓冲区信息)、资源集扫描、对象复制、终止(具有尝试次数)。
  • 还显示了“其他”时间,例如选择CSet、参考处理、参考排队和释放CSet所花费的时间。
  • 显示了伊甸园、幸存者和总堆占用率。

简单输出

[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 将详细程度设置为“最精细”。与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启动以来经过的时间。

Sample Output

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日志输出定义了许多术语。以下示例显示了日志的输出,并解释了将在其中找到的术语和值。

Note: 更多信息请查看 Poonam Bajaj’s Blog post on G1 GC logs.

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

并行时间

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 –工作开始的时间戳t

Note: 日志按线程id排序,并且在每个条目上都是一致的

外部根扫描

[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 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 - 必须更新已完成但尚未在暂停开始之前由并发优化线程处理的任何缓冲区。时间取决于卡片的密度。卡片越多,花的时间就越长。

扫描记忆集

[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 (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 (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工作线程结束

[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工作

[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其他部分的瓶颈(例如,分层的代码缓存占用率的增加)。

清除 CT**

[Clear CT: 0.6 ms]

清除资源集扫描元数据的卡片表所用的时间

其他

[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]

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

综述

在本文中,您已经获得了javajvm中包含的G1垃圾收集器的概述。首先,您了解了堆和垃圾收集器是任何javajvm的关键部分。接下来,您回顾了如何使用CMS收集器和G1收集器进行垃圾收集。接下来,您了解了G1命令行开关以及使用它们的最佳实践。最后,您了解了记录GC日志中包含的对象和数据。

在本教程中,您学习了:

  • Java JVM的组件
  • G1收集器概述
  • CMS收集器综述
  • G1收集器综述
  • 命令行开关和最佳实践
  • 关于G1的日志记录

资源

欲了解更多信息和相关信息,请访问这些网站和链接。

Credits

  • Curriculum Developer: Michael J Williams
  • QA: Krishnanjani Chitta
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页