Getting Started with the G1 Garbage Collector(译)

原文连接:Getting Started with the G1 Garbage Collectorhtml

概述

目的

这篇教程包含了G1垃圾收集器使用和它如何与HotSpot JVM配合使用的基本知识。你将会学到G1收集器内部是如何运做的,切换到使用G1的命令和记录其操做的日志选项。java

完成时间

大概一个小时(我操,一个小时我勉强能够看完,要是这样边翻译边看仍是须要点时间的呀git

简介

这个OBE(我不知道OBE是什么意思)包含了Java中Java虚拟机(JVM)G1垃圾收集(GC)的基本知识。在这个OBE的第一部分,在介绍垃圾收集的同时也介绍了一下JVM。接下来,将带大家一块儿回顾一下CMS收集器如何与Hotspot协同工做的。而后,就是一步一步的引导你们学习当G1垃圾收集器搭配Hotspot的时候,JVM中的垃圾收集器是如何工做的。在这以后,将会有一部分讲解G1垃圾收集器的垃圾收集的命令行选项。最后你将会学习使用G1收集器时的垃圾收集日志选项。web

硬件和软件要求

下面列举了硬件和软件的要求:算法

  • 运行Windows XP及后来版本,Mac OS或者Linux的PC。注意目前只在Windows 7上亲自测试过,而不是在因此的平台上都测试过。可是,在OS X或者Linux上一切都运行良好。同时,若是你的机器是多核的就更好了。
  • Java 7 Update 9或者之后的版本
  • 最新的Java 7演示和样例Zip压缩文件

前提

在开始本教程以前,你应该:数据库

若是你尚未安装JDK的话,请先下载并安装最新版本的Java JDK(JDK 7u9或者以后版本)。
Java 7 JDK 下载编程

以及从相同地方下载样例压缩文件。解压并将其放到目录总。好比:C:\javademos浏览器

Java概述(如下都是废话。。。)

来不想翻译的,算了,仍是慢慢翻吧安全

Java是Sun Microsystems公司于1955年发布的一门变成语言以及计算平台。它是支撑包括由Java编写的utilities,游戏和商务应用等程序的底层技术。Java运行在世界范围内超过8亿5千万台PC上以及数十亿的设备中,包括移动设备和TV。Java由一系列关键组件组成,而且他们做为一个总体,构成了Java平台。服务器

Java运行时版本

当你下载了Java以后,你就得到了Java运行时环境(JRE)。JRE包括Java虚拟机(JVM),Java平台核心类,和支撑Java平台的库。以上3个都是在你的电脑上运行Java程序必不可少的。在Java 7中,Java程序能够做为操做系统的桌面应用运行,用Java Web Start能够从Web上安装并做为桌面应用运行,或者在浏览器中(使用JavaFX)做为Web嵌入程序运行。

Java编程语言

Java是一门面向对象的变成语言,它有以下特性。

  • 平台无关性- Java应用被编译成字节码,这些字节码存储在类文件中并加载到JVM中。因为应用是在JVM中运行的,因此它们能够在不一样的系统和设备中运行。
  • 面向对象 - Java是一门面向对象的语言,从C和C++中吸收了不少特性并加以改进。
  • 自动垃圾收集 - Java能够自动分配和回收内存,因此应用程序不用受内存分配和回收等困扰。
  • 丰富的标准库 - Java包括了不少预约义的对象,这些对象能够很方便的完成输入/输出,网络通讯以及其余数据处理的任务。

Java开发套件

Java Development Kit(JDK)是一套用于开发Java应用的工具。有了JDK,你能够编译Java语言编写的程序,而且在JVM上运行它们。除此以外,JDK也提供了一套用于打包和发布你的应用的工具。JDK和JRE共享Java应用程序接口(Java API)。Java API是预打包的库的集合,开发者能够利用Java API来开发他们的应用程序。有了Java API来完成许多开发中共同的任务使得开发过程更方便,好比字符串处理,日期/时间的处理,网络通讯和数据结构的实现(好比链表,映射,栈和队列等)。(tmd,翻译的好累。。。

Java虚拟机(Java Virtual Machine)

Java虚拟机是一种抽象的计算机器。JVM是一个程序,可是对于那些在它上面运行的程序而言,它像是一个机器。这样一来,Java程序都是用同一套接口和库来编写的。每一个在特定平台上面实现的Java虚拟机,都会把Java编程指令翻译成运行在本地操做系统上的指令和命令。如此,Java程序可以得到平台无关性。

 

JVM第一个实现的原型是由Sun Microsystems公司完成的,在相似于Personal Digital Assistant(PDA)的手持设备上模拟运行Java虚拟机指令。 Oracle's current implementations emulate the Java virtual machine on mobile, desktop and server devices, but the Java virtual machine does not assume any particular implementation technology, host hardware, or host operating system. It is not inherently interpreted, but can just as well be implemented by compiling its instruction set to that of a silicon CPU. It may also be implemented in microcode or directly in silicon.

 

Java虚拟机其实并不知道什么是Java编程语言,它仅仅知道一种特殊的二进制格式,即类文件格式。一个类文件中包含了Java虚拟机指令(字节码)和符号表,以及其余的一些辅助信息。

 

为了安全起见,Java虚拟机对类文件中的代码施加了严格的句法和结构的限制。然而,任何可以表达成有效类文件的变成语言均可以在Java虚拟机中运行。因为平台无关性以及普遍可用性,其余语言的实现者也能够将起放到Java虚拟机中运行。(1) The Java Virtual Machine

探索JVM的架构

Hotspot架构

HotSpot JVM的架构能够有力的支持高性能和大规模的可扩展性的特征和能力。例如,HotSpot JVM JIT编译器可以生成动态优化的代码。换句话说,它们在Java程序运行的时候能够进行优化决策,而且对于底层系统架构来讲能够生成高质量的本地机器码。除此以外,经过成熟的改进以及连续的运行环境工程化和多线程的垃圾收集器,HotSpot JVM甚至在最大型的计算机中均可以得到高可扩展性。

 

image

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

 

Hotspot中的关键组件

下图中描述了JVM中和性能密切相关的组件。

 

image

图2 JVM中和性能密切相关的组件

 

在进行性能调优的时候,JVM中有3个组件须要关注。Java堆是你的对象数据存储的地方。这块区域是由Java虚拟机开启时所选择的垃圾收集器来管理的。大多数的调优选项都是根据你的应用场景设置合适的堆尺寸以及选择最合适的垃圾收集器。JIT编译器对于性能也有很大的影响,可是对于新版本的JVM来讲,这个已经不多须要调整了。

性能指标

通常来讲,当对一个Java应用程序调优的时候,关注的焦点一般是响应或者吞吐量这两者之一。在本教程的后面会回过头来再看这两个概念。

响应速度

响应速度指的是一个应用或者系统对请求过来以后反应的快慢。典型的例子有:

桌面UI对事件的反应快慢

一个网站返回页面速度有多快

一个数据库查询返回数据有多快

对于讲求响应速度的应用来讲,长时间的暂停是不可接受的。因此须要在短期内就能够响应。

吞吐量

吞吐量关注的是使一个应用在特定的时间内完成最大的工做量。衡量吞吐量的例子有如下几种:

在给定时间内完成的事务。

一个小时内一个批处理程序能够完成的工做量。

在一个小时内一个数据库能够完成的查询数量。

对于吞吐量来讲,能够忍受长时间的暂停。因为高吞吐量的任务关注的是以长时间的基准,快速响应时间并不在考量的范围以内。

G1垃圾收集器

G1垃圾收集器是一款适用于服务器的垃圾收集器,这些服务器通常有多个处理器以及很大的内存。它可以很好的知足high probability同时又能达到很高的吞吐量。Oracle JDK7 update 4以及后来版本都彻底支持G1垃圾收集器。G1垃圾收集器专为如下应用设计的:

可以像CMS收集器同样和应用线程一块儿并发操做。

可以压缩可用空间,而不会出现因垃圾收集致使的漫长的暂停时间。

须要更多可预测的GC暂停时间。

不想牺牲不少的吞吐量性能。

不须要过多的Java堆。

 

G1计划做为Concurrent Mark-Sweep(CMS)垃圾收集的长期替代。和CMS相比较,G1有不少不一样之处使得G1比CMS更好。其中的一个特色是,G1是一个带压缩的垃圾收集器。G1可以充分的压缩可用内存来避免出现使用细粒度的可用空间列表进行内存分配,而是依赖于区域。这极大地简化了垃圾收集的一部分工做,最大程度地减小了可能存在的碎片化问题。同时,G1比CMS提供了更多的可预测的垃圾收集暂停,而且容许用户指定想要的暂停目标。(感受挺牛逼的啊

G1 Operational Overview(这个Operational怎么翻译。。。。)

 

之前的垃圾收集器(serial,parallel,CMS)都将堆分为如下3个部分:年轻代,老年代,和固定内存大小的永久代。

 

 

image

图3 之前的垃圾收集器对堆的划分

全部的内存中的对象最终都会落到这3个区域的其中一个。可是,G1收集器采用了一种不一样的方式。

 

image

图4 G1垃圾收集器对堆的划分

 

堆被划分为同等大小的堆区域的集合,每一块在虚拟内存中都的地址都是相接的。(这句话的意思是在虚拟内存中你能够想象这些块都是放在一块儿的,可是在实际的物理内存中它们可能相隔n远)某些区域的集合被分配相同的角色(好比eden,survivor,old),就像在之前的垃圾收集器中那样,可是它们并无固定的大小。这在内存的使用上提供了极大的弹性。

 

在进行垃圾回收的时候,G1的操做方式相似于CMS收集器。G1进行并发的全局标记阶段来决定整个堆中对象是否存活。在标记阶段完成以后,G1会知道哪些区域的大部分是空的。它会先收集这些区域,从而会有大量的空闲空间。这就是为何这种垃圾收集方法叫作Garbage-First(同志们,这就是为啥它叫G1啊)。正如它的名字所暗示的那样,G1将它的收集和压缩活动集中在那些尽量装满可回收对象的区域,即,垃圾。G1使用暂停预测模型来知足用足自定义的暂停时间目标,根据特定的暂停时间目标来选择准备回收区域的数量。(有点好奇它的暂停预测模式是怎么构建的?

 

被G1识别为到已经达到可回收时机的区域将会将会用撤走(离场?evacuation)的方法进行回收。G1会将堆中一个或者多个区域中的对象复制到堆中的一个单一的区域,在这个过程当中会同时对内存进行压缩和释放。这种evacuation的动做在多处理器的CPU上是并发进行,这样能够减小暂停时间并提升吞吐量。如此,每一次垃圾回收时,G1都会在用户自定义的暂停时间中持续工做并减小内存的碎片化。这种能力超过了以往的任何方法。CMS(Concurrent Mark Sweep)垃圾收集器不会对内存进行压缩。ParallelOld垃圾收集器只会对整个堆进行压缩,所以致使了至关长时间的暂停。

 

必需要注意到G1并非一个实时的垃圾收集器。它会以很高的可能性来知足设定的暂停时间目标,但这并非必定的。根据以前的垃圾收集数据,G1会对用户自定的目标时间内可能进行回收的区域个数进行估算。所以,G1收集器对收集的区域会有一个合理准确的模型,而后它利用这种模型来决定在暂停时间内回收哪些以及有多少区域会被回收。

 

注意:G1既有并发(和应用线程一块儿执行,好比refinement,标记和清理)阶段也有并行阶段(多线程,好比stop-the-world)。Full GC仍然是单线程的,若是调优得当的话,你的应用应该能够避免full GC。

G1空间占用(Footprint)

若是你从ParallelOldGC或者CMS收集器转而使用G1,你颇有可能发现JVM进行占用的空间更大了。这其中大部分和"审计"数据结构有关,好比Rembered Sets和Collection Sets。

Remembered Sets或者RSets记录那些到一个给定的区域中对象的引用。在堆上每一个区域都有一个RSet。RSet使得一个区域的并行和独立收集变得可能。RSets对真个空间占用的影响小于5%。

Collection Sets又或者叫CSets是那些将会在下一次GC中被回收的区域集合。全部在CSet中存活的对象都会在下一次GC是被evacuated(copied/moved)。这些区域的集合能是Eden,survivor或者老年代。CSets对JVM占用内存的影响小于1%。

建议使用G1垃圾收集器的场景

G1第一个关注点是为用户运行的那些须要很大的堆内存又要短的GC延迟提供一种解决方案。这意味着堆的大小在6GB或者更大时,稳定的可预测的暂停时间将小于0.5秒。

对于目前使用CMS或者ParallelOldGC垃圾收集器的应用,若是具备如下一个或者超过一个特征的,换成G1收集器将会对性能有很大提高。

  • Full GC停留的时间太长或者太频繁。
  • 新对象分配的速率或者对象老化的速率随时间变化很大。
  • 比预期长得多的垃圾收集时间或者压缩暂停的时间(比0.5到1秒还久)。

注意:若是你正在使用CMS或者ParallelOldGC而且你的应用并无受长时间的垃圾收集暂停时间之苦,那么最好仍是保持使用你当前的垃圾收集器。对于使用最新的JDK而言,切换到G1并非必须的。

回顾CMS中的垃圾收集

回顾通常的垃圾收集以及CMS

 

并发标记清除(Concurrent Mark Sweep)收集器(又称为concurrent low pause collector)收集老年代。它试图经过和应用线程并发工做时最大程度地完成垃圾收集任务来最小化暂停时间。一般CMS不会复制或者压缩存活的对象。这种垃圾收集方式不会移动存活的对象。若是碎片化致使问题了,那么采用的方法就是分配一个更大的堆。

注意:CMS收集器使用和并行收集器同样的算法来回收年轻代。

CMS垃圾收集的过程

 

CMS经过如下阶段来完成对堆中老年代的收集工做:

 

 

Phase

Description

(1)初始标记
(Stop the World事件)
在老年代的对象被标记为可达,其中包括那些从年轻代可达的对象。相对于minor GC的暂停时间,初始标记致使的暂停时间很短。
(2)并发标记 在Java应用线程运行的同时遍历老年代中可达的对象。从已被标记的对象开始,而且从根节点依次遍历可达的对象。mutators从并发阶段2,3和5开始执行而且任何在CMS阶段分配的对象(包括被promotion的对象)都当即被标记为存活。
(3)从新标记
(Stop the World事件)
找到那些在并发标记阶段在并发标记收集器完成跟踪以后因为Java应用线程更新致使错过的对象。
(4)并发清除 收集那些在标记阶段标记为不可达的对象。死亡对象的收集增长了能够用后面分配的空闲列表的空间。死亡对象的Coalescing可能发生在这个阶段。注意存活的对象并无移走。
(5)从新设定 经过清理数据结构准备下一次的并发收集。

 

回顾垃圾收集的步骤

接下来,让咱们回顾一下CMS垃圾收集器是怎么一步一步进行垃圾收集的。

Next, let's review CMS Collector operations step by step.

1. CMS垃圾收集器中的堆结构

堆被分红了3个空间。

 

image

图5 CMS中的堆划分

 

年轻代被分红了1个Eden空间和2个survivor空间。老年代连续的空间(contiguous)。

2. CMS中的年轻代GC是如何进行的?

在下图中年轻代用绿色标注了,而老年代则是蓝色的。若是你的程序运行了一下子的话,你的Java堆可能就长成如今这样。对象分散在老年代中。

 

image

图6 CMS中对象的分布

在CMS中,老年代中的对象都是原位回收的。它们不会被处处移动。只有在执行Full GC的时候,老年代的空间才会被压缩。

 

3. 年轻代的收集

 

存活的对象都从Eden空间和Survivor空间复制到另外一个Survivior空间中。任何到达了年龄阈值的对象都会提高到老年代中。

image

图7 年轻代的收集

 

4. 年轻代收集以后

 

image

图8 年轻代收集以后

 

新提高到老年代的中的对象在图8中都用深蓝色标注。绿色的对象都是未被提高到老年代的年轻代中存活下来的对象。

 

5. CMS中老年代的收集

两个stop-the-world的事件会发生:初始标记和从新标记。当老年代到达了必定的占用率以后,CMS收集便拉开了序幕(kicked off)。

 

image

图9 CMS中老年代的收集

 

(1)初始标记中存活的(可到达的)对象会被标记,这是一个短暂停的过程。

(2)并发标记在应用线程执行的同时找到存活的线程。

最后在(3)从新标记阶段,会找到以前(2)中并发标记中被错过的对象。

 

6. 老年代的收集 - 并发清除

 

在以前阶段中没有被标记的对象都会被回收。但并不会对标记的对象压缩。

 

image

图10 老年代的收集 - 并发清除

 

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

 

7. 老年代的收集 - 清除以后

 

在(4)清除阶段以后,你能够发现,不少的内存都被释放掉了。同时也会发现没有进行压缩过程。

 

image

图11 老年代的收集 - 清除以后

 

最后,CMS收集器会到(5)阶段,即重置阶段并等待下一次GC的到来。(GC。。。我不纯洁了)

 

G1垃圾收集器详细介绍

G1垃圾收集器详细介绍

G1垃圾收集器采用不一样的方式来对堆进行分配。下面的图片一步一步回顾了G1系统。

1. G1堆结构

堆内存被划分为相同大小的固定区域。

 

image

 

在启动的时候JVM会选择区域的大小。JVM一般会将堆分为2000个区域,每一个区域大小大概为1到32Mb之间。

 

G1堆的划分

实际上,这些区域被映射到逻辑上的Eden,Survivor和Old Generation Space。

 

image

 

图中不一样的颜色表明了每块区域对应的角色。存活的对象被evacuated从一个区域到另外一区域。区域的回收被设计为并行模式,既能够和应用线程共存,也能够和stop-the-world。正如锁演示的那样,这些区域能够被分配到Eden,survivor和old generation。除此以外,还有被被称之为Humongous区域的第4种类型的区域。这些区域使用来容纳那些占标准区域大小50%甚至以上的对象的。它们存储时做为相邻的区域。最终最后这种类型的区域是堆中未使用的区域。

注意:在这篇教程写的时候,对humongous对象的回收并无进行优化。所以,你须要避免建立这类型的对象。

 

G1中的年轻代

整个堆大约被分为2000个区域。最小的区域是1Mb,最大的区域是32Mb。蓝色的区域持有老年代对象而绿色的区域则是持有年轻代对象。

 

image

 

注意,这些区域并不像之前的垃圾收集器中那样须要相邻。

G1中的一次年轻代收集

存活的对象会别evacuated到一个或则更多的survivor区域中。若是达到了老化阈值,某些对象会被提高到老年代的区域中。

 

image

 

这是一次Stop-The-World的暂停。Eden的大小和Survivor的大小会被计算出来为下一次年轻代的GC作准备。会保持审计信息来帮忙计算大小。同时也考虑到暂停时间之类的目标。这种方式使得很是容易地从新调整区域的大小,只要须要,能够随时的扩大或者缩小。

G1中年轻代收集结束时

存活的对象被evacuated到survivor区域或者老年代中。

 

image

 

最近提高的对象用深蓝色表示。Survivor区域则用绿色表示。

用一下的话来总结一下G1中年轻代的收集:

  • Java堆是被分为不少区域的单块内存空间。
  • 年轻代的内存由一系列不连续的空间组成。
  • 年轻代的收集是会致使Stop-The-World的。全部的应用线程在这个过程当中会中止。
  • 年轻代的收集是多线程并行进行的。
  • 存活的对象都被复制到新的survivor或者老年代区域中。

Old Generation Collection with G1

就像CMS收集器同样,G1收集器被设计为对于老年代对象的收集低暂停时间。小表中描述了G1收集器中老年代的G1收集阶段。

 

G1收集阶段 - 并发标记Cycle阶段

G1收集器会对堆中的老年代执行如下阶段。要注意其中某些阶段是在年轻代收集中的。

 

阶段

描述

(1)初始标记(Stop-The-World) 这是一个会Stop-The-World的事件。在G1中,这个阶段是借助(piggyback)于一次正常的年轻代GC的。标记survivor(root regions)中有引用到老年代中的对象。
(2)Root Region扫描 扫描survivor区域中那些会进入老年代的引用。当程序恢复运行的时候会进行。这个阶段必需要在年轻代垃圾收集以前完成。
(3)并发标记 找到整个堆上存活的对象。这个在应用运行的时候发生。这个阶段能够被年轻代的垃圾收集打断。
(4)从新标记阶段(Stop-The-Word) 完成堆上存活对象的标记。使用被称之为snapshot-at-the-beginning(SATB)的算法,这要比CMS收集器中的算法快得多。
(5)清理(Stop-The-World和并发)
  • 执行对存活对象的审计并完成空闲区域的释放。(Stop-The-World)
  • Scrubs Remembered Sets。(Stop-The-World)
  • 重置空闲的区域并将它们返回到空闲列表。(Concurrent)
(*)复制(Stop-The-World) 将存活的对象evacuate或者copy到新的未使用的区域中都是Stop-The-World的暂停。这些和年轻代区域时候完成,在日志中输出为[GC pause (young)]。或者在年轻代区域和老年代区域中同时发生,日志为[GC Pause (mixed)]。

 

定义了以上的阶段以后,咱们来看一下这些阶段如何与G1收集器中的老年代交互的。

 

6. 初始标记阶段

存活对象的初始标记是附着于年轻代的垃圾收集的。在日志中的输出是标为GC pause (young)(initial-mark)。

 

image

 

7. 并发标记阶段

若是有空的区域被找到(用"X"表示的),它们立刻会在从新标记阶段被清除掉。一样,决定是否存活的审计信息也会被计算出来。

 

image

 

8. Remark Phase

空的区域会被移走和收回。并且全部区域的是否存活都计算出来了。

 

image

 

9. 复制/清理阶段

G1选择那些具备最低"存活性"的区域,这些区域可以以最快的速度收集。而后这些区域会在和年轻代GC相同的时间被回收。这日志中的输出是[GC pause (mixed)]。所以,年轻代和老年代的回收都是在同一时间。

 

image

 

10. 复制/清理以后的阶段

选择的区域被回收并被压缩到深蓝色的区域中,深蓝色的区域在下图中显示了。

 

image

 

老年代中GC的总结

 

这里有些关键的地方要对老年代进行总结一下:

  • 并发标记阶段:存活性的信息会在应用程序运行的时候同时进行。存活信息代表了那些在evacuation阶段最适宜被收回的区域。这里没有像CMS中那样的Sweeping阶段。
  • 从新标记阶段:使用Snapshot-at-the-Beginning算法,要比CMS中的算法更快。彻底为空的区域会被回收。
  • 复制/清理阶段:年轻代和老年代会在同一时刻被回收。老年代区域的选择是基于它们的存活性的。

命令行选项和最佳实践

 

这一部分咱们来看一下G1中的命令行选项。

基础的命令行

为了激活G1垃圾收集器,可使用: -XX:+UseG1GC

这里有一个启动Java2Demo,这个例子包含在JDK的demos中

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:InitatingHeapOccupancyPercent=45 当堆的空间占用达到这么多以后会启动一个并发的垃圾收集周期。G1中正是使用的这种整个对的占用,而不是某个代中的占用。若是设置为0就表示"进行constant垃圾收集周期"。这个选项的默认值是45(也就是对的占用达到了45%)。

 

最佳实践

这里提供了一些你在使用G1垃圾收集器时应该遵循的一些最佳实践。

 

不要设置年轻代的大小

 

经过-Xmn来显式地设置年轻代的大小会干预(meddles)到CG1收集器的默认行为。

  • G1将不会再遵循收集时的暂停时间目标。因此大致上(in essence),设置了年轻代的大小会禁用掉暂停时间目标。
  • G1将不能随着须要而扩大或者收缩年轻代空间的大小。因为大小被固定了,对于其大小不会由任何改变。

 

响应时间度量

设置XX:MaxGCPauseMillis=<N>,而不是使用平均响应时间(ART),是的知足目标的几率达到90%或者更多。这意味着90%的用户发出请求时将不会超过预设的时间目标。记住,暂停时间是一个目标,而不是必须知足的一个条件。

 

Evacuation Failure会怎么样?

 

为了survivors或者提高年轻代而进行GC是,会由于JVM用光了java堆而致使promotion failure。堆因为已经达到了最大的尺寸而不能继续扩展。这在用-XX:+PrintGCDetails时会to-space overflow而显示。这将致使花费增长。

 

GC会继续进行使得空间必须被释放。

复制失败的对象将必须提高到老年代中。

任何在CSets中的RSets的更新将从新生成。

全部以上的步骤的花费都很是大。

 

若是避免Evacuation Failure

 

为了不Evacuation Failure,考虑一下选项。

增长堆的大小:增长-XX:G1ReservePercent=n,默认的值是10。G1会建立一个false ceiling经过试图使reserve memory空间以免须要更多的"to-space"。

更早地开始标记周期。

使用-XX:ConcGCThreads=n选项来增长标记线程。

 

完整的G1垃圾收集的选项

 

一下是完整的G1收集选项,记得使用上面的最佳实践哦。

选项及其默认值 描述
-XX:+UseG1GC 使用G1垃圾收集器
-XX:MaxGCPauseMillis=n 设置最大的暂停时间目标。这是一个软性的目标,而且JVM会努力达到这个目标。
-XX:InitiatingHeapOccupancyPercent=n 启动并发GC的堆内存使用的百分比。这个选项被GC用来根据整个Heap占用百分比来触发一次并发的垃圾收集周期,而不是由于某一代的占用率。若是这个值为0,表示进行"do constant GC周期"。默认值是45。
-XX:NewRatio=n 新/老代的大小之比,默认是2。
-XX:SurvivorRatio=n eden/survivor空间的比,默认值是8。
-XX:MaxTenuringThreshold=n 最大的老化阈值,这个默认值是15。
-XX:ParallelGCThreads=n 设置垃圾收集并行阶段的线程数量。默认的值随着JVM运行的平台不一样而不一样的。
-XX:ConcGCThread=n 垃圾收集在并行阶段所使用的线程数。默认的值随着JVM运行的平台不一样而不一样的。
-XX:G1ReservePercent=n 为了减小promotion失败可能性而设置的heap的保留的false ceiling。默认值是10。
-XX:G1HeapRegionSize=n 在G1中,Java堆被分为同一大小的区域。这个选项设定了区域的大小。这个值是根据所分配的堆的大小不一样而不一样的。最小值为1Mb,最大值为32Mb。

 

G1中的GC日志

咱们要讲的最后一个主题是用来分析G1垃圾收集器的日志信息。这个部分提供你能使用收集信息和垃圾收集日志中打印的信息的选项。

 

设置日志细节

你能够设置3中不一样垃圾收集的日志级别。

(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。这个选项提供了一下信息:

  • 每一个阶段的平均,最小和最大时间
  • Root Scan,RSet更新(已经处理的buffer信息),RSet Scan,对象复制,终结(尝试的次数)。
  • 同时也显示了其余时间好比选择CSet花费的时间,引用处理,引用入列和释放CSet。
  • 显示Eden,Survivor和整个堆的占用。

 

输出样例

 

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

Determing Time

有一些开关使用来调整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]

 

理解GC日志

为了理解日志,这个部分定义了一些在GC输入的日志中所用的术语。一下输出显示了一些GC日志中扩展的术语。

 

注意:若是须要更多的信息,请访问Poonam Bajaj's Blog post on G1 GC logs

 

GC日志术语索引

 

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 – 垃圾线程开始的时间戳
Note: The logs are ordered on thread id and are consistent on each entry

注意:这个日志是按照线程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 - 用于扫描外部的根对象花的时间(好比,像执行堆的system dictionary)

 

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 - 已经完成的可是尚未被concurrent refinement线程处理的缓冲。Time depends on density of the cards. The more cards, the longer it will take.

 

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 - Look for pointers that point into the Collection Set.

 

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 – The time that each individual thread spent copying and evacuating objects.

 

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 - When a worker thread is finished with its particular set of objects to copy and scan, it enters the termination protocol. It looks for work to steal and once it's done with that work it again enters the termination protocol. Termination attempt counts all the attempts to steal work.

 

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 – Timestamp when the individual GC worker stops.

GC worker time – Time taken by individual GC worker thread.

 

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 – The time (for each GC thread) that can't be attributed to the worker phases listed previously. Should be quite low. In the past, we have seen excessively high values and they have been attributed to bottlenecks in other parts of the JVM (e.g., increases in the Code Cache occupancy with Tiered).

 

Clear CT

[Clear CT: 0.6 ms]
Time taken to clear the card table of RSet scanning meta-data

 

Other

[Other: 6.8 ms]
Time taken for various other sequential phases of the GC pause.

 

CSet

[Choose CSet: 0.1 ms]
Time taken finalizing the set of regions to collect. Usually very small; slightly longer when having to select old.

 

Ref Proc

[Ref Proc: 4.4 ms]
Time spent processing soft, weak, etc. references deferred from the prior phases of the GC.

 

Ref Enq

[Ref Enq: 0.1 ms]
Time spent placing soft, weak, etc. references on to the pending list.

 

Free CSet

[Free CSet: 2.0 ms]
Time spent freeing the set of regions that have just been collected, including their remembered sets.

 

总结

(终于到总结了,好累)

在这篇OBE中,你已经了解到了Java JVM中的G1垃圾收集器了。你要了解的第一个是Heap和GC什么是任何Java JVM中的关键组件。接下来你要了解的是CMS和G1是如何工做的。接下来就是你要了解使用G1的时的命令行以及最佳实践。最后就是你要知道GC日志中记录对象和数据。

 

在这篇教程中,你已经学到了:

Java JVM中的组件

G1垃圾收集器的概览

CMS垃圾收集器的概览

G1的命令行和最佳实践

G1中的GC日志

资源

访问以下的网站能够得到更多的资源

Java HotSpot VM Options

The Garbage First(G1) Garbage Collector

Poonam Bajaj G1 GC Blog Post

Java SE 7: Develop Rich Client Applications

Java Performance - Charlie Hunt and Binu John

Oracle Learning Library

致谢

Curriculum Developer: Michael J Williams

QA: Krishnanjani Chitta

相关文章
相关标签/搜索