Garbage First(G1)垃圾收集器

引言:G1垃圾收集器采用一个略微不同的手段来解决并行、串行以及CMS GC的众多缺陷。对于大的Java堆来说,通过将Java堆拆分成一个个分区,G1会比其他垃圾收集器有更好的综合表现。
本文选自《Java性能调优指南》。

  G1垃圾收集器采用一个略微不同的手段来解决并行、串行以及CMS GC的众多缺陷。G1将堆拆成一系列的分区,这样在一个时间段内,大部分的垃圾收集操作就只是在一个分区内执行,而不是整个堆或整个(老年)代。

  在G1里,年轻代就是一系列的内存分区,这意味着不用再要求年轻代是一个连续的内存块。类似地,老年代同样也是由一系列的分区组成。这样也就不需要在JVM运行时考虑哪些分区是老年代,哪些是年轻代。事实上,G1通常的运行状态是映射G1分区的虚拟内存随着时间的推移在不同的代之间前后切换。一个G1分区最初被指定为年轻代,经过一次年轻代的回收之后,整个年轻代分区都被划入到未被使用的分区中,那它也就可以被使用在别的地方了。

  一个可用分区能被用于或指定为年轻代或老年代分区。很可能在完成一个年轻代收集之后,一个年轻代的分区在未来的某个时刻被用于老年代分区。同样地,在一个老年代分区完成收集之后,它就成为了可用分区,在未来某个时候作为一个年轻代分区来使用。

  G1年轻代的收集方式是并行stop-the-world。在垃圾收集线程执行过程中,并行stop-the-world回收将暂停所有Java应用线程,而垃圾回收的工作也将通过多个线程来分担。与其他HotSpot垃圾收集器一样,一旦发生一次年轻代垃圾收集,整个年轻代都会被回收。

  而G1老年代的垃圾收集方式与其他HotSpot垃圾收集器有着极大的不同。G1老年代的收集不会为了释放老年代的空间就要求对整个老年代做回收。相反,在任一时刻只有一部分老年代分区会被回收,并且,这部分老年代分区将与一次年轻代收集一起被收集。

贴士
术语混合(mixed)垃圾收集就是用来描述这种一部分老年代分区与年轻代收集结合在一起进行的收集。因此,混合GC就是在一次垃圾收集事件中,所有年轻代分区以及一部分老年代分区将会被回收。换句话说,混合GC就是将要被回收的年轻代与年老代分区的组合。

  与CMS GC类似,当遇到一些极端情况时,诸如老年代空间被消耗完了,会有一个安全措施来收集和压缩整个老年代。

  撇开安全模式下的收集不谈,一个G1老年代收集是由一系列阶段组成,某些是并行stop-the-world的,某些是并行并发的。也就是说,某些阶段是多线程的同时会暂停所有应用线程,而其他阶段是多线程的,但可以与应用线程同时运行。

  当超过Java堆的占用阈值,G1就会启动一次老年代收集。要注意到有一点非常重要,那就是G1中的堆占用阈值,这是根据老年代占用空间与整个Java堆空间相比较得出的。熟悉CMS GC的读者会记得,CMS触发老年代收集所用的占用阈值只是相对于老年代空间本身而言的。在G1中,一旦达到或超过内存堆的占用阈值,一次并发stop-the-world方式的初始标记阶段就会被安排执行。

  初始标记阶段会跟着下一次年轻代收集同时进行。一旦初始标记阶段结束,就会触发一个并发多线程的标记阶段,标记老年代中所有的存活对象。当并发标记阶段结束,并行stop-the-world的重新标记阶段就被启动,标记那些因为在标记阶段同时执行的应用线程导致产生错过的对象。到重新标记阶段结束,G1就拥有了老年代分区的完整信息。如果碰巧老年代分区里一个存活对象都没有,那么在下一个阶段——清除阶段,不用做额外的垃圾收集工作就可以被回收再利用。

  同样也是在重新标记阶段结束,G1能识别出最适合回收的老年代分区集合。

贴士
在垃圾收集过程中收集的分区集合可以称为收集集合(CSet)。

  选择哪些分区被包含在一个CSet里,是基于有多少空间可以被释放以及G1暂停时间目标。在完成CSet识别之后,G1就在接下来的几次年轻代垃圾收集过程中对CSet中的分区进行回收。也就是说,在接下来的几个年轻代垃圾收集中,除了年轻代分区,还有一部分的老年代分区也将被回收。这就是前面提到的垃圾收集事件中的混合GC类型。

  不管是年轻代还是老年代,G1会把每个收集过垃圾的分区中的存活对象转移到一个可用分区中。一旦存活对象被转移掉,那这个年轻代分区(可能还有老年代分区)就会被回收为可用分区。

  将各老年代分区中的存活对象转移到可用分区会带来一个很有吸引力的结果——在虚拟地址空间里每个转移对象都是前后相连的,对象和对象之间没有碎片化的空余空间。我们回忆一下,CMS、并行以及串行垃圾收集器都需要一个full GC来压缩老年代,而这个压缩动作需要扫描整个老年代空间。

  因为G1以每个分区为基础做垃圾收集操作,所以它适用于大尺寸的Java堆。垃圾收集工作的数量可以被限制在一个小范围的分区集合内,哪怕Java堆尺寸可能会相当大。

  G1暂停时间的最大来源是年轻代收集和混合收集,所以G1的设计目标之一就是允许用户设置GC暂停时间目标。G1会尝试通过调整Java堆尺寸大小的方式来满足设定的暂停时间目标。它会根据暂停时间目标自动调整年轻代的尺寸和总的Java堆尺寸。暂停时间目标越短,年轻代空间就越小,总的堆空间就越大,使得老年代空间相对就越大。

  G1的设计目标就是把必要的调整限定在设置最大的Java堆空间和指定GC暂停时间目标上。另外,G1还被设计成可以通过一个内部的启发式算法来做自我调整。在写这本书的时候,G1的启发式算法就是HotSpot GC开发活动开展的最活跃的地方。同样到写这本书时为止,G1也许会要求一些特定场景下的额外调优,不过开发优秀的启发式算法的先决条件已经具备并且前景很可观。至于如何对G1进行调优的建议。

  综上,对于大的Java堆来说,通过将Java堆拆分成一个个分区,G1会比其他垃圾收集器有更好的综合表现。在局部压缩的帮助下,G1解决了Java堆碎片,它的绝大部分工作都通过多线程的方式完成。

  截止到写这本文时,G1首要针对的是那些有合理短暂停的大尺寸Java堆的用例,当然还有那些正在使用CMS垃圾收集器的应用。也有计划用G1来处理吞吐量用例,但对于那些追求高吞吐量,同时能容忍更长GC暂停的应用来说,目前并行垃圾收集器是更好的选择。

  本文选自《Java性能调优指南》,点此链接可在博文视点官网查看此书。
                    
  想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。
                       

时间: 2024-09-12 01:17:42

Garbage First(G1)垃圾收集器的相关文章

G1垃圾收集器介绍

原文链接,译者:Greenster 简介 Oracle在JDK7 update 4之后开始完全支持G1垃圾收集器,G1是一个针对多处理器大容量内存的服务器端的垃圾收集器,其目标是在实现高吞吐量的同时,尽可能的满足垃圾收集暂停时间的要求.G1在执行一些Java堆空间中的全区域操作(如:全局标记)时是和应用程序线程并发进行的,因此减少了Java堆空间的中断比例.(译者注:可简单理解为减少了Stop-the-World的时间比例) 技术说明 G1收集器通过下面一些方法实现了高性能和减少暂停时间的目的.

深入理解G1垃圾收集器

G1 GC是Jdk7的新特性之一.Jdk7+版本都可以自主配置G1作为JVM GC选项:作为JVM GC算法的一次重大升级.DK7u后G1已相对稳定.且未来计划替代CMS.所以有必要深入了解下: 不同于其他的分代回收算法.G1将堆空间划分成了互相独立的区块.每块区域既有可能属于O区.也有可能是Y区,且每类区域空间可以是不连续的(对比CMS的O区和Y区都必须是连续的).这种将O区划分成多块的理念源于:当并发后台线程寻找可回收的对象时.有些区块包含可回收的对象要比其他区块多很多.虽然在清理这些区块时

垃圾收集器Serial 、Parallel、CMS、G1

这里介绍4个垃圾收集器,如果进行了错误的选择将会大大的影响程序的性能.     时至今日,仍然有两个事情困扰着开发人员:垃圾收集(GC)和了解异性(程序猿的悲鸣),后者我确实不太了解,因为我被前者搞的无暇顾及怎么了解异性,特别是当知道在JAVA8中对这一区域有了很大的改进和提升还有移除了PermGen和以一些新的令人兴奋的调优.     当我们谈到垃圾回收时,我们绝大多数都知道利用它的概念在我们日常的编程中.但是,当问题出现时,会发现很多是我们不知道的.JVM 最大误区之一就是它只有一个垃圾回收

我们的垃圾收集器

(译者注:这篇博文发表在2008年,虽然年代有些久远,但是文中说到的垃圾收集器我们至今还在使用,作者也谈到了对于G1垃圾收集器的期望.) 最近我在白板上给客户化了一个图表,他们似乎对这个有点兴趣,所以我想我可以重画一遍来给你们消遣. 每个蓝色的盒子都代表了一个收集器,用来收集某一代.黄色区域中的蓝色盒子是用来收集新生代的,灰色区域中的蓝色盒子是用来收集老年代的. Serial"是一个单线程.stop-the-world.使用复制算法的收集器. "ParNew" 是一个多线程.

Boehm-Demers-Weiser Conservative Garbage Collector 7.2发布 垃圾收集器

The Boehm-Demers-Weiser conservative garbage collector 是一款C++ and C++ 的垃圾收集器.它可以使用C语言作为中间代码来实现多种编程语言,能够被用来作为一个C或C++程序的检漏仪.一个旧版本的垃圾收集器也包含GNU编译器(GCC)分布. Boehm-Demers-Weiser Conservative Garbage Collector 7.2该版本增加了许多改进和修正. 软件信息:http://www.hpl.hp.com/per

jdk1.7 HotSpot虚拟机 怎么查看使用的哪种垃圾收集器

问题描述 jdk1.7 HotSpot虚拟机 怎么查看使用的哪种垃圾收集器 怎么查看虚拟机使用的哪种垃圾收集器?是G1,还是CMS? 启动java的参数中没有配置-XX:+UseG1GC这种参数 $ ./java -version java version "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08,

jvm系列(三):GC算法 垃圾收集器

概述 垃圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 java 堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的. 对象存活判断 判断对象是否存活一般有两种方式: 引用计数:每个对象有一个引用计数属性

JVM垃圾收集器

参考文献:周志明<深入理解Java虚拟机>第二版 垃圾收集器就是 GC 具体的实现,不同厂商,不同版本,针对虚拟机不同的分区都有不一样垃圾收集器 图. 基于JDK 1.7 update 14的 HotSpot虚拟机包含的收集器 Serial 收集器 这个收集器是一个单线程收集器,在它进行收集工作时,必须暂停其他所有的工作线程,直到收集结束,这种工作方式又被称为"Stop the World" 它采用复制算法 因为单线程,所以会造成停顿,但也使得它简单而高效 适用于新生代 M

jvm系列(三):java GC算法 垃圾收集器

GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 java 堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的.   对象存活判断 判断对象是否存活一般有两种方式: 引用计数: