您的位置:首页 > 编程语言 > Java开发

HotSpot VM GC收集器的易混淆的名称问题

2017-08-08 17:23 519 查看
最近分析HotSpot VM GC日志,就各种收集器的名称搞晕掉了,幸好参考R大(RednaxelaFX )一些回复和文章。整理在此文,以方便自已日后查阅,也可让有需要的同学少走弯路,追本溯源,一切从DefNew的来因说起。

DefNew: 是使用-XX:+UseSerialGC(新生代,老年代都使用串行回收收集器)时启用
ParNew: 是使用-XX:+UseParNewGC(新生代使用并行收集器,老年代使用串行回收收集器)或者-XX:+UseConcMarkSweepGC(新生代使用并行收集器,老年代使用CMS)时启用。

原本HotSpotVM里并没有并行GC,当时只有NewGeneration。新生代,老年代都使用串行回收收集。后来准备加入新生代并行GC,就把NewGeneration改名为DefNewGeneration,然后把新加的并行版叫做ParNewGeneration。

DefNewGeneration、ParNewGeneration都在Hotspot VM”分代式GC框架“内。但后来有个开发不愿意被这个框加憋着(证明了那句:所有壮举都不是在框架内产生的),自已硬写了个新的并行GC。测试后效果还不错。于是这个也放入VM的GC中。这就是我们现在看到的ParallelScavenge。

这个时候就出现个两个新生代的并行GC收集器:ParNewGeneration,ParallelScavenge。

(R大: Scavenge或者叫scavenging GC,其实就是copying GC的另一种叫法而已。HotSpot VM里的GC都是在minor GC收集器里用scavenging的,DefNew、ParNew和ParallelScavenge都是,只不过DefNew是串行的copying GC,而后两者是并行的copying GC。 由此名字就可以知道,“ParallelScavenge”的初衷就是把“scavenge”给并行化。换句话说就是把minor GC并行化。至于full GC,那不是当初关注的重点。 )

把GC并行化的目的是想提高GC速度,也就是提高吞吐量(throughput)。所以其实ParNew与ParallelScavenge都可叫做Throughput GC。
但是在HotSpot VM的术语里“Throughput GC”通常特指“ParallelScavenge”

ParallelScavenge和ParNew都是并行GC,主要是并行收集young gen,目的和性能其实都差不多。最明显的区别有下面几点:

ParallelScavenge以前是广度优先顺序来遍历对象图的,JDK6的时候改为默认用深度优先顺序遍历,并留有一个UseDepthFirstScavengeOrder参数来选择是用深度还是广度优先。在JDK6u18之后这个参数被去掉,ParallelScavenge变为只用深度优先遍历。ParNew则是一直都只用广度优先顺序来遍历。

ParallelScavenge完整实现了adaptive size policy,而ParNew及“分代式GC框架”内的其它GC都没有实现(倒不是不能实现,就是麻烦+没人力资源去做)。所以千万千万别在用ParNew+CMS的组合下用UseAdaptiveSizePolicy,请只在使用UseParallelGC或UseParallelOldGC的时候用它。

由于在“分代式GC框架”内,ParNew可以跟CMS搭配使用,而ParallelScavenge不能。当时ParNew GC被从Exact VM移植到HotSpot VM的最大原因就是为了跟CMS搭配使用。

在ParallelScavenge成为主要的throughput GC之后,它还实现了针对NUMA的优化;而ParNew一 直没有得到NUMA优化的实现。

上面说ParallelScavenge并行收集young gen,那old/perm gen呢?

ParallelScavenge因为和其他几个GC不在一个框架内,最初的ParallelScavenge体系对老年代的回收拿的是VM的“分代式框架“里在 Serial Old收集器的代码,改了接口,负责full GC,
并命名为: PSMarkSweep(=“ParallelScavenge的MarkSweep”),其实就是仍然串行收集。
这里的ParallelScavenge已经不是Parallel Scavenge(并行新生代收集器),而是一套GC框架体系。

为了名称与VM“分代式框架”里的收集器好区别,在这套体系时,新生代收集器叫:PSScavenge,老年代收集器叫:PSMarkSweep。(PS看成是ParallelScavenge缩写,作为前缀)。

后来,因为未知的原因,老年代GC的并行化,没有在VM”分代式GC框架“中完成,而选择了在ParallelScavenge框架中。其成果就是使用了LISP2算法的并行版的full GC收集器,名为PSCompact(=“ParallelScavenge-MarkCompact”),收集整个GC堆。

当启用-XX:+UseParallelOldGC时,用的就是PSScavenge+PSCompact的组合。
当启用-XX:+UseParallelGC时,用的就是PSScavenge+ PSMarkSweep的组合。
(在Jconsole查看时,PSCompact、PSMarkSweep都显示为PSMarkSweep
DefNew显示为Copy,Serial Old(MSC)显示为MarkSweepCompact)。

Guest Author有一幅关于GC收集器的示意图:



黄色部分的用于新生代的收集器,紫灰色部分的用于老年代的收集器。连接线表示两者可以配合使用。

你会发现分代式GC框架有收集器(Serial (就是DefNew),ParNew,CMS,MSC)可以任意搭配。而ParallelScavenge体系里的PSScavenge(图示中的ParallelScavenge),只能和其同一体系的Parallel Old搭配。
至于ParallelScavenge和Serial Old的连线,就是因为上文提到的PSMarkSweep,他是从VM“分代式框架“里抽出来的Serial Old收集器,加了一层包装而已。

?号那个应该就是现在G1,他又是另一个体系框架内开发的,所以六亲不认。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java GC