JVM垃圾收集器

我最近在白板上为客户花了这张图。他们看起来很喜欢(或许是出于礼貌)。因此我想把它重画一下,让你们也欣赏一下。

JVM-垃圾收集器.jpg

每个蓝色的方块都代表一个收集器。新生代的垃圾收集工作由黄色区域中的蓝色方块负责,老年代的垃圾收集工作由灰色区域中的蓝色方块负责。

收集器

"Serial":
这是一个全局停顿的复制收集器,它使用单个GC线程执行垃圾收集工作。

"ParNew":
这是一个全局停顿的复制收集器,它使用多个GC线程执行垃圾收集工作。它和"Parallel Scavenge"收集器的区别是它进行了一些强化,使得它可以和CMS一起使用。例如,"ParNew"会执行所需的同步,以便它可以在CMS的并发阶段运行。

"Parallel Scavenge":
这是一个全局停顿的复制收集器,它会使用多个GC线程。

"Serial Old":
这是一个全局停顿的标记-清除-压缩收集器,它使用的是单个GC线程。

"CMS":
这是一个并发低停顿的收集器。

"Parallel Old":
这是一个压缩收集器,它使用多个GC线程。

收集器的搭配使用

GC参数 收集器组合
UseSerialGC "Serial" + "Serial Old"
UseParNewGC "ParNew" + "Serial Old"
UseConcMarkSweepGC "ParNew" + "CMS" + "Serial Old"
UseParallelGC "Parallel Scavenge" + "Serial Old"
UseParallelOldGC "Parallel Scavenge" + "Parallel Old"

备注:

UseConcMarkSweepGC就是: "ParNew" + "CMS" + "Serial Old"。在收集老年代时大多数时间使用的是"CMS"。当出现并发模式错误时,就会使用"Serial Old"。

FAQ

1、UseParNew和UseParallelGC它们俩个都使用多个GC线程收集新生代。那么它们谁更快呢?

这个问题没有一个正确的答案。大部分情况下,它们在执行时都是等同的,但是我也见过在不同环境中有时它们中的一个会比另一个表现的要好。如果想使用GC ergonomics,但是只有UseParallelGC(UseParallelOldGC)支持它,那么那就是你要使用的。

2、为什么"ParNew" 和 "Parallel Old"不能在一起工作?

"ParNew"的书写风格是每个分代都会为其收集工作提供特定的接口。例如,"ParNew" (和 "Serial")实现了space_iterate()该方法会对新生代中的每个对象施加一个行为。当使用"CMS"或"Serial Old"收集老年代时,GC可以使用space_iterate()方法对新生代中的对象执行一定的工作。这使得收集器的"混合-匹配"(mix-and-match)得以工作,但是也为收集器的维护和增加新的收集器造成了一定负担。收集器的数量越多该负担的影响越大。

而对于"Parallel Scavenge"总是知道老年代时如何收集的,并且可以直接地调用"Serial Old"收集器中的代码。"Parallel Old"并不是按照"ParNew"的风格写的,因此把它和"ParNew"匹配在一起使用需要大量的工作。另外,我们最终希望"Parallel Scavenge"和"Parallel Old"匹配组合在一起使用,并清除一些将"Parallel Scavenge"和二者协同工作所需的钩子代码。

请不要过多考虑我上面使用的示例。他们不值得你花时间。

3、我如何将"CMS"和"Serial"组合在一起使用?

-XX:+UseConcMarkSweepGC -XX:-UseParNewGC

不要使用-XX:+UseConcMarkSweepGC 和-XX:+UseSerialGC。虽然这看起来想一个逻辑组合,但是它将产生一个收集器组合冲突的报错信息,JVM将无法启动。很遗憾。这个是我们的问题。

4、"G1"收集器 ?

"G1"这个蓝色方块代表的是我们当前正在开发的新的垃圾收集器,称为Garbage First 或 G1。G1将提供如下特性:
(1). 更可预测的GC停顿
(2). 更好的GC工效
(3). 低停顿,无碎片
(4).收集时的并行和并发
(5).更佳的堆空间使用率

G1横跨新生代-老年代的界限,因为它只在逻辑意义上才是一个分代收集器。G1把堆空间划分成很多区域,在GC期间可以收集这些区域中的一些子集。说它是逻辑分代,那是因为它会动态地选择一组区域充当新生代,这些区域将在下次GC时被收集(就像收集新生代那样)。

用户可以为停顿时间指定一个目标,G1将进行评估(基于过去的收集进行评估),在给定的停顿时间目标下应该收集多少区域。该区域集被称为回收集,G1将在下次GC时对其进行回收。

G1会选择先回收垃圾最多的区域(Garbage First垃圾优先,明白了吧?),以便于得到最大的回收收益。
G1压缩使得碎片化问题要小的多。为什么有这个问题呢? 这是因为存在部分填充的区域所导致的内部碎片。

正是因为堆不再静态地分成新生代和老年代,所以也就不存在新生代和老年代大小不平衡的问题。

除了停顿时间目标,用户还可以指定在某些周期内可以消耗在GC上的时间片。(如,在下个100秒,不要消耗超过10秒的收集时间)。对于此目标(在100秒内,10秒的GC时间),G1会选择一个它可以在10秒内收集的回收集,并在距离上个收集90秒后调度该回收任务。你可以看到坏用户会再次把收集时间指定为0。这仅仅是个目标,并非承诺。

如果G1如我们所期待的那样,它将成为我们替代"ParNew" + "CMS"的低停顿收集器。如果你要问我什么时候G1才能商用,那么请原谅我紧闭的嘴。这是我们团队的最高优先级项目,但是它毕竟是软件开发项目,因此通常有很多未知数。它将由JDK7推出。正如我们所关心的,越早越好。

更新于2月4日。是的,我编辑的是一个已经发布的博客。如果你有ACM门户网站的访问权限的话,这里有一个G1论文 http://portal.acm.org/citation.cfm?id=1029879

说明

本文章翻译自Oracle博客,原文请查看

our-collectors

你可能感兴趣的:(JVM垃圾收集器)