(译者注:这篇博文发表在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”的标识)。