JDK8垃圾回收调优指南--(9)G1

原文:Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide--Garbage First Garbage Collector

G1垃圾收集器是一种服务器风格的垃圾收集器,针对的是内存较大的多处理器机器。它试图在满足GC停顿时间目标的同时,高概率的实现高吞吐量。整个堆操作(例如'global marking')是与应用线程并发执行的。这可以防止与堆大小或实时数据大小成比例的中断。

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

堆被划分为一组大小相同的堆区域,每个区域都是一个连续的虚拟内存。G1执行一个'concurrently global marking phase'(并发的全局标记阶段)来确定堆中对象的活性。标记阶段完成后,G1知道哪些区域大部分是空的。它首先收集这些区域,这通常会产生大量的自由空间。这就是为什么这种垃圾收集方法称为'Garbage-First'(垃圾优先)。顾名思义,G1将其收集和压缩活动集中在堆中可能充满可回收对象(即垃圾)的区域。G1使用一个“暂停预测模型”来满足用户定义的暂停时间目标,并基于暂停时间目标选择要收集的区域数量。

G1将对象从堆的一个或多个区域复制到堆上的一个区域,并在此过程中压缩和释放内存。在多处理器上并行执行这种转移,以减少停顿时间并增加吞吐量。因此,每次垃圾收集时,G1都在不断地减少碎片。这超出了前面两种方法(CMS和并行)的能力。CMS(并发标记清除)垃圾收集不做压缩。并行收集器压缩只执行全堆压缩,这会导致相当长的停顿时间。

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

G1的第一个关注点就是为那些运行高内存,低GC延迟的应用用户提供一个解决方案。这意味着约为6gb或更大的堆,且稳停顿时间稳定在0.5秒以下。

如果应用程序具有以下一个或多个特性,那么使用CMS或并行压缩的应用程序将受益于切换到G1。

  • 超过50%的Java堆被存活数据占用。
  • 对象分配率或提升率差异显著。
  • 应用程序正在经历不必要的长时间垃圾收集或压缩暂停(超过0.5到1秒)。

G1计划作为CMS的长期替代品。将G1与CMS进行比较,可以发现G1与CMS之间的差异,从而使G1成为更好的解决方案。
一个不同之处在于G1是一个压缩收集器。此外,G1提供了比CMS收集器更稳定且可预测的GC停顿,并允许用户指定所需的暂停目标。

与CMS一样,G1是为需要更短GC停顿的应用设计的。

G1将堆划分为固定大小的区域(灰色框),如图9-1所示:

Heap Division by G1

G1在逻辑上是分代的。一组空区域被指定为逻辑年轻代。在图中,年轻代是浅蓝色的。分配是在逻辑年轻代之外完成的,当年轻代已满时,将对该区域集进行垃圾收集(年轻代收集)。在某些情况下,可以同时收集年轻区域集之外的区域(深蓝色的旧区域)。这被称为'mixed collection'。在图中,正在收集的区域用红色框标记。图中显示了一个'mixed collection',因为同时收集了年轻域和老年区域。G1是一个压缩收集,它将活动对象复制到选定的、最初为空的区域。根据存活对象的年龄,可以将对象复制到存活区域(用“S”标记)或旧区域(没有特别显示)。以“H”为标记的区域含有大对象,超过了区域的一半,并经过特殊处理;详见Humongous Objects and Humongous Allocations

Allocation Failure

与CMS一样,G1在应用程序运行时并发地完成其收集的部分内容,并且存在应用程序分配对象的速度快于垃圾收集器恢复空闲空间的风险。有关类似的CMS行为,请参阅并发模式故障。在G1中,类似的故障发生在G1将存活数据从一个区域复制到另一个区域时(耗尽Java堆)。复制是为了压缩存活的数据。如果在回收过程中找不到空闲(空)区域,则会发生分配失败(因为没有空间来分配正在被转移区域中的存活对象),此时'stop-the-world'(STW),完成'full collection'。

Floating Garbage

对象可能在G1收集期间死亡而无法收集。G1使用了一种名为'snapshot-at-the-beginnint'(SATB)的技术,以确保垃圾收集器能够找到所有存活的对象。SATB声明,为了回收的目标,在并发标记开始时存活的任何对象(整个堆上的标记)都被认为是存活的。SATB允许浮动垃圾,其方式类似于CMS增量更新。

Pauses

G1暂停应用,将存活对象复制到新区域。这些暂停可以是只收集年轻区域的'young collection'暂停,也可以是回收年轻区域和老年区域的'mixed collection'暂停。与CMS一样,当应用程序停止时,会有一个'final pause'或'remark pause'来完成标记。
CMS也有一个初始标记暂停,G1将'initial mark'作为转移暂停的一部分。G1在一次回收的末尾会有一个清理阶段,部分是STW,部分是并发的。STW部分的清理阶段标识空区域,并确定下一次回收的候选老年区域。

Card Tables and Concurrent Phases

如果垃圾收集器没有收集整个堆(增量收集),那么垃圾收集器需要知道从堆的未收集部分到正在收集的堆部分的指针在哪里。这通常适用于一个分代垃圾收集器,在分代垃圾收集器中,堆的未收集部分通常是老年代,而堆的收集部分是年轻代。保存这些信息的数据结构(老年代指针指向年轻代对象)是一个'remembered set'。'card table'是'remembered set'的一种特殊类型。
Java HotSpot VM使用字节数组作为'card table'。每个字节都被称为'card'。'card'对应于堆中的一组地址。将卡片弄脏意味着将字节的值更改为脏值;脏值可能包含老年代到年轻代的新指针,位于卡片覆盖的地址范围内。

处理'card'意味着查看'card',看看是否有老年代到年轻代的指针,并可能对这些信息进行处理,比如将其转化成另一个数据结构。

G1有并发标记阶段,标记应用中的存活对象。并发标记从转移暂停的末尾阶段(初始标记工作在此完成)延伸到remark。
并发清理阶段将回收清空的区域添加到空闲区域列表中,并清除这些区域的'remembered set'。此外,并发优化线程根据需要运行,以处理被应用程序写入弄脏的、可能具有跨区域引用的'card table'条目。

Starting a Concurrent Collection Cycle

如前所述,在'mixed collection'中的年轻区域和老年区域都会被回收。为了收集老年区域,G1对堆中的存活对象做了一次完整的标记。这种标记由并发标记阶段完成。当整个Java堆的占用率达到参数'InitiatingHeapOccupancyPercent'的值时,将启动并发标记阶段。使用命令行选项'-XX:InitiatingHeapOccupancyPercent=<NN>'设置此参数的值。占有率'InitiatingHeapOccupancyPercent'的默认值是45。

Pause Time Goal

使用'MaxGCPauseMillis'为G1设置暂停时间目标。G1使用一个预测模型来决定在目标暂停时间内可以完成多少垃圾回收工作。在回收结束时,G1选择下一次回收中将要回收的区域(the collection set)。'collection set'将包含年轻区域('collection set'大小的和决定逻辑年轻代的大小)。G1控制GC停顿的长短,部分原因是通过选择回收集中年轻区域的数量。与其它垃圾收集器一样,您可以在命令行上指定年轻代的大小,但是这样做可能会妨碍G1实现目标GC停顿时间的能力。除了停顿时间目标之外,还可以指定暂停发生的时间段长度。您可以指定使用此时间跨度(GCPauseIntervalMillis)和暂停时间目标的最小mutator使用量。'MaxGCPauseMillis'的默认值是200毫秒。GCPauseIntervalMillis(0)的默认值相当于对时间跨度没有要求。

友情提示:最后一段垮掉了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值