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


DefNew: 是使用-XX:+UseSerialGC(新生代,老年代都使用串行回收收集器)时启用

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

 

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

 

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

 

这个时候就出现个两个新生代的并行GC收集器:ParNewGenerationParallelScavenge

 

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

 

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

 

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

 

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

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

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

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

 

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

 

ParallelScavenge因为和其他几个GC不在一个框架内,最初的ParallelScavenge体系对老年代的回收拿的是VM的分代式框架“里在 Serial Old收集器的代码,改了接口,负责full GC

并命名为: PSMarkSweep(=“ParallelScavengeMarkSweep”),其实就是仍然串行收集。

这里的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查看时,PSCompactPSMarkSweep都显示为PSMarkSweep

  DefNew显示为Copy,Serial Old(MSC)显示为MarkSweepCompact)。


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

wKiom1mJg3Hw-ClQAAE6RDl8LR8949.png-wh_50

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


你会发现分代式GC框架有收集器(Serial (就是DefNew),ParNewCMSMSC)可以任意搭配。而ParallelScavenge体系里的PSScavenge(图示中的ParallelScavenge),只能和其同一体系的Parallel Old搭配

至于ParallelScavengeSerial Old的连线,就是因为上文提到的PSMarkSweep,他是从VM分代式框架“里抽出来的Serial Old收集器,加了一层包装而已。

 

?号那个应该就是现在G1,他又是另一个体系框架内开发的,所以六亲不认