22 - 23 - 24
ParNew + CMS 工作原理
ParNew 是回收新生代的收集器，其回收过程前面已经说说清楚了，ParNew 是G1出现前大规模使用的收集器(现在可能很多依然在用)，其特点就是多线程收集。
CMS  是回收老年代的收集器，其使用 标记-清除-整理 算法。总体分为以下步骤
1 初始标记：
初始标记会进入STW状态，标记的是目前GC Roots'直接'关联的对象
2 并发标记：
并发标记，这个阶段是最耗时的 但是是并发运行的并且不会STW，标记的是老年代中所有对象是否被GC Roots '间接' 引用，是GC Roots追踪过程。
3 重新标记 :
在第二阶段运行时会有新的对象和垃圾，这个是之前没标记出来的，这里会再次进入STW状态，但是因为对象很少，所以速度是很快的。
4 并发清理
这个阶段也是很耗时的，但是是并发处理，不会阻塞系统运行。

CPU线程紧张问题：
在并发标记中因为老年代中存活对象比较多，这个这个追踪花费时间会比较多，并发清理要在大量对象中清理对象，也是比较耗时的。这两个过程都是和系统并发运行的，所以是比较耗费CPU线程资源的。
Concurrent Mode Failure问题：
在并发清理过程中,CMS只是回收了之前标记的垃圾对象，但是这个过程之中可能会伴随新的Minor GC，也就是又会有对象进入老年代，这些对象当然不是之前已经标记的对象，称为"浮动垃圾"。
在JDK1.6中 当老年代内存占用达到了92%，就进行CMS回收。也就是说预留了8%的内存让新生代对象进入老年代。但是如果恰恰此时8%不够怎么办？那么此时就会强制使用Serial Old收集器来代替CMS，
直接让系统进入STW状态，一次性清理垃圾对象，不允许系统线程运行了，等Serial Old运行结束了之后再回复系统线程。 这就造成了系统假死了。
内存碎片问题：
上面标记整理之后，可能会存在内存碎片问题，如果内存碎片太多，会导致老年代无法找出连续可用空间，继而再次引发Full GC，但是JVM会在上一次Full GC的并发标记之后再次进入STW状态，把老年代
存活对象挪到一起去，解决碎片问题

老年代触发GC的时机
第一 是老年代可用内存小于新生代全部对象的大小，如果没开启空间担保参数，会直接触发Full GC，所以一般空间担保参数都会打开；
第二 是老年代可用内存小于历次新生代GC后进入老年代的平均对象大小，此时会提前Full GC；
第三 是新生代Minor GC后的存活对象大于Survivor，那么就会进入老年代，此时老年代内存不足。
第四 “-XX:CMSInitiatingOccupancyFaction”参数。如果老年代可用内存大于历次新生代GC后进入老年代的对象平均大小，但是老年代已经使用的内存空间超过了这个参数指定的比例，也会自动触发Full GC。