我们的垃圾收集器

(译者注:这篇博文发表在2008年,虽然年代有些久远,但是文中说到的垃圾收集器我们至今还在使用,作者也谈到了对于G1垃圾收集器的期望。)

最近我在白板上给客户化了一个图表,他们似乎对这个有点兴趣,所以我想我可以重画一遍来给你们消遣。

每个蓝色的盒子都代表了一个收集器,用来收集某一代。黄色区域中的蓝色盒子是用来收集新生代的,灰色区域中的蓝色盒子是用来收集老年代的。

  • Serial”是一个单线程、stop-the-world、使用复制算法的收集器。
  • “ParNew” 是一个多线程、stop-the-world、使用复制算法的收集器。和”Parallel Scavenge”不同,它可以和”CMS”收集器一起使用。比如说,”ParNew”做了同步需要,以便它能在CMS的并发阶段继续运行。
  • “Parallel Scavenge” 是一个多线程、stop-the-world、复制算法的收集器。
  • “Serial Old”是一个单线程 、stop-the-world、使用标记-清除-压缩的收集器。
  • “CMS”是一个并发、短暂停的收集器。
  • “Parallel Old”是多线程、使用压缩算法的收集器。

对于JDK6,可以使用-XX来标记我们的收集器。

  • UseSerialGC 是”Serial”+”Serial Old”
  • UseParNewGC 是”ParNew”+”Serial Old”
  • UseConcMarkSweepGC 是”ParNew”+”CMS”+”Serial Old”。大多数时候是使用”CMS”来手机老年代,当并发模式失败的时候使用”Serial Old”
  • UseParallelGC 是”Parallel Scavenge”+”Serial Old”
  • “CMS”是一个并发、短暂停的收集器。
  • UseParallelOldGC 是”Parallel Scavenge”+”Parallel Old”

FAQ

1.UseParallelGC 和UseParNewGC 都是多线程来收集新生代,哪个更快?

这个问题没有准确的答案。大部分他们性能相当,但是我还是见过在不同的情景下其中一个比另一个更好。

2.为什么”ParNew”和”Parallel Old”不能同时运行?

在”ParNew” 的风格下,每个被收集的代对于它的收集都提供一个确定的接口,比如说,”ParNew”实现了 space_iterate()方法,这个方法将对新生代中的每个对象应用一个操作。当使用”CMS” 或”Serial Old” 收集老年代的时候。GC可以使用 space_iterate() 来对在新生代中的的对象进行操作。这让收集器可以混合工作,但是会造成收集器维持的一些负担。并且这个负担看起来是收集器的二次方。作为一种选择,”Parallel Scavenge”总是知道老年代是怎么收集的,并且能直接调用在”Serial Old” 收集器中的代码。”Parallel Old”不是”ParNew”风格的,所以不会和”ParNew”匹配。顺便说一下,我们希望最终只有”Parallel Scavenge”和”Parallel Old”可以进行匹配。

对于我上面的使用的例子,不要想太多。他们就是这样设计的,不要浪费太多时间。

3.怎样把”Serial”和”CMS”一起使用

使用 -XX:+UseConcMarkSweepGC -XX:-UseParNewGC,而不要使用 -XX:+UseConcMarkSweepGC和 -XX:+UseSerialGC。虽然这样的组合看起来合乎逻辑,但是这会导致一个信息表示收集器之间有冲突,JVM将不会启动。

4.上图中蓝色盒子中的问号是不是一个排版错误?

这个盒子代表一个正在开发的新的收集器,叫做Garbage First G1收集器。G1将会提供:

  • 更加可预测的GC停顿
  • 更加高效的GC
  • 没有碎片下更短暂的停顿
  • 并行和并发收集器
  • 更好的堆利用

G1跨过了新生代和老年代的范围,因为它是一个只有逻辑区域的分代收集器。G1把堆划分为独立区域,在一次GC中可以收集这片区域的一个子集。它是一个逻辑分代是因为它动态的选择一片区域作为新生代,这片区域将在下一次GC中被回收。

用户可以指定一次停顿的目标,G1将会做一个评估(基于过去的收集),评估有多少个区域在这次停顿(停顿目标) 中可以被收集。这片区域被称之为一个回收集合,G1将在下一次GC中去收集它。

G1能选择有最多垃圾的区域进行收集(所以叫Garbage First)。

G1采用压缩算法所以碎片不是问题。为什么是个问题呢?因为部分填满的区域会导致内部的碎片。

Java堆没有被静态的分为一个新生代和老年代,所以他们尺寸的不平衡在这里不是问题。

和指定一次停顿时间一起,用户可以指定一部分花费在GC上的时间(比如说在下一次100秒钟不要花费超过10秒钟来进行垃圾收集)。对于这个目标(在100秒内的10秒GC时间),G1能选择一个回收集合,这个集合是G1预测它能在10秒内收集完的区域。有可能看到一个用户在下一次收集中指定0秒的垃圾收集时间,但这只是一个目标,不是一个保证。

如果G1能按我们期待的那样工作,它将取代 “ParNew” + “CMS”. 成为我们的低停顿收集器。如果你问什么时候可以准备好G1,请你不要抱怨我的沉默。这是我们团队最高优先级的工作,但这是一个软件开发,所以经常会有未知事件。它将在jdk7中推出。对我们而言,越早越好。(译者注:关于G1的论文发表在2004年,而这篇博客发表在2008年,作者就预料到了不确定性。确实,直到2012年的JDK7u4,Sun公司才认为G1达到了足够成熟的商用程度,移除了“Experimental”的标识)。

转载自 并发编程网 - ifeve.com

时间: 2024-07-28 20:28:08

我们的垃圾收集器的相关文章

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,

JAVA垃圾收集器与内存分配策略详解_java

引言 垃圾收集技术并不是Java语言首创的,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.垃圾收集技术需要考虑的三个问题是: 1.哪些内存需要回收 2.什么时候回收 3.如何回收 java内存运行时区域的分布,其中程序计数器,虚拟机栈,本地方法区都是随着线程而生,随线程而灭,所以这几个区域就不需要过多考虑回收问题.但是堆和方法区就不一样了,只有在程序运行期间我们才知道会创建哪些对象,这部分内存的分配和回收都是动态的.垃圾收集器所关注的就是这部分内存. 一 对象

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

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

深入理解JVM之四:详解垃圾收集器

前言 前面已经对垃圾收集算法有了较为详细的介绍,这里我们将对JVM中具体的垃圾回收器进行介绍,在虚拟机规范中并没有对垃圾回收器如何实现具体介绍,因此每个厂商的垃圾回收器可能会完全不同,但是我们介绍的是基于JDK1.7之后的Hotspot虚拟机(包括前面对Java虚拟机的介绍也是基于jdk1.7版本的).在Hotspot中,虚拟机的收集器主要有下: 可以看到垃圾收集器是按对象的分代来划分的,可以用线条连接的垃圾回收器表示两者可以配合使用.可以看到新生代垃圾收集器有Serial.ParNew.Par

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

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

G1垃圾收集器介绍

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

java对象生命周期-一个对象被垃圾收集器回收了为什么还要卸载

问题描述 一个对象被垃圾收集器回收了为什么还要卸载 一个对象被垃圾收集器回收了为什么还要卸载?被gc回收了不是已经不存在了吗? 解决方案 说反了吧,先卸载才能回收 http://www.cnblogs.com/mengdd/p/3594608.html 解决方案二: 自己 Delete 可靠一些,且实时性高. 靠 GC 不知道是什么时候才能收回.

垃圾收集器与内存分配策略

虚拟机如何判断对象是否存活? 1.引用计数算法   给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就是不可能再被使用的.   考虑一种情形:对象objA和objB都有字段instance,赋值令objA.instance=objB和objB.instance=objA;除此之外,这两个对象再无任何引用,实际上这两个对象以及不可能再被访问,但是它们因为互相引用着对方,导致它们的引用计数都不为0,于是引用计数算法无法通知GC收

[jjzhu学java]之深入理解JVM之垃圾收集器与内存分配策略

深入理解JVM之垃圾收集器与内存分配策略 如何判断对象已经消亡 引用计数算法 根搜索算法 引用 深入理解JVM之垃圾收集器与内存分配策略 java中对象的创建需要的内存都是在java堆中申请的,所以垃圾收集的区域就是对java堆和方法区的内存区域进行GC. 如何判断对象已经消亡 垃圾收集器的主要任务就是找出已经"消亡"的对象,将其标记并清除其说用内存的过程,如何判断某个对象已经"消亡",不同的虚拟机有不同的判断策略 引用计数算法 引用计数(Reference Cou

Garbage First(G1)垃圾收集器

引言:G1垃圾收集器采用一个略微不同的手段来解决并行.串行以及CMS GC的众多缺陷.对于大的Java堆来说,通过将Java堆拆分成一个个分区,G1会比其他垃圾收集器有更好的综合表现.本文选自<Java性能调优指南>. G1垃圾收集器采用一个略微不同的手段来解决并行.串行以及CMS GC的众多缺陷.G1将堆拆成一系列的分区,这样在一个时间段内,大部分的垃圾收集操作就只是在一个分区内执行,而不是整个堆或整个(老年)代. 在G1里,年轻代就是一系列的内存分区,这意味着不用再要求年轻代是一个连续的内