Parallel Scavenge的特点是它的关注点与其他收集器不同,CMS等收集器的关注点尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。所谓吞吐量就是CPU用于运行用户代码与CPU总消耗时间的比值。
高吞吐量和停顿时间短的策略相比,主要强调任务更快完成,而后者强调用户交互体验。
Parallel Scavenge提供两个参数控制垃圾回收停顿时间:-XX:MaxGCPauseMillis和-XX:GCTimeRatio
MaxGCPauseMillis允许的值是一个大于零的毫秒数,收集器将尽力保证内存回收话费的时间不超过设定值。GC停顿时间缩小是以牺牲吞吐量和新生代空间来换取的,也就是要使停顿时间更短,垃圾回收的频率会增加。
GCTimeRatio的值是一个大于0小于100的整数,也就是垃圾收集时间占总时间的比率。设为19,则允许最大GC时间就占总时间的5%(1/(1+19)),默认99.
Parallel Scavenge收集器也被称为吞吐量优先收集器。
还有一个参数, -XX:+UseAdaptiveSizePolicy,是个开关参数,打开后会自动调整Eden/Survivor比例,老年代对象年龄,新生代大小等。这个参数也是Parallel Scavenge和ParNew的重要区别。
Serial Old收集器是Serial的老年代版本,同样是单线程收集器,使用标记-整理算法。主要是client模式下的虚拟机使用
两大用途:
在JDK1.5及之前的版本中与Parallel Scavenge搭配使用。
作为CMS收集器的后备预案。在并发收集发生Concurrent Mode Failure时使用。
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法。在JDK1.6中才开始使用。由于之前的版本中,Parallel Scavenge只有使用Serial Old作为老年代收集器,其吞吐量优先的设计思路不能被很好的贯彻,在Parallel Old收集器出现后,这两者的配合主要用于贯彻这种思路。
CMS收集器Concurrent Mark Sweep 以获取最短回收停顿时间为目标的收集器,比较理想的应用场景是B/S架构的服务器。
基于标记-清除算法实现,运行过程分成4个步骤:
初始标记(需要stop the world),标记一下GC Roots能直接关联到的对象,速度很快。
并发标记,进行GC Roots Tracing的过程。
重新标记(需要stop the world),为了修正并发标记时用户继续运行而产生的标记变化,停顿时间比初始标记长,远比并发标记短。
并发清除
缺点:
CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是因为占用了一部分CPU资源而导致应用程序变慢,总吞吐量就会降低。CMS默认启动的回收线程数为(CPU数量+3)/4。为了解决这一情况,有一个变种i-CMS,但目前并不推荐使用。
CMS收集器无法处理浮动垃圾(floating garbage).可能会出现concurrent mode failure导致另一次full gc的产生。在CMS的并发清理阶段,由于程序还在运行,垃圾还会不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理掉它们,只好留到下一次GC再处理。这种垃圾称为浮动垃圾。同样由于CMS GC阶段用户线程还需要运行,即还需要预留足够的内存空间供用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被灌满了再进行收集而需要预留一部分空间提供并发收集时的程序运作使用。默认设置下,CMS收集器在老年代使用了68%的空间后就会被激活。这个值可以用-XX:CMSInitiatingOccupancyFraction来设置。要是CMS运行期间预留的内存无法满足程序需要,就会出现concurrent mode failure,这时候就会启用Serial Old收集器作为备用进行老年代的垃圾收集。
空间碎片过多(标记-清除算法的弊端),提供-XX:+UseCMSCompactAtFullCollection参数,应用于在FULL GC后再进行一个碎片整理过程。-XX:CMSFullGCsBeforeCompaction,多少次不压缩的full gc后来一次带压缩的。
G1收集器G1. Garbage first,尚在研发阶段,使用标记-整理算法,精确控制停顿,极力避免全区域垃圾收集。前面的收集器进行的收集范围都是整个新生代或老年代,而G1将整个JAVA堆划分为多个大小固定的独立区域,跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次在允许的收集时间里,优先回收垃圾最多的区域。
理解GC日志 [GC [PSYoungGen: 8987K->1016K(9216K)] 9984K->5056K(19456K), 0.0569611 secs] [Times: user=0.03 sys=0.02, real=0.06 secs] [GC [PSYoungGen: 8038K->1000K(9216K)] 12078K->10425K(19456K), 0.0709523 secs] [Times: user=0.05 sys=0.00, real=0.07 secs] [Full GC [PSYoungGen: 1000K->0K(9216K)] [ParOldGen: 9425K->8418K(10240K)] 10425K->8418K(19456K) [PSPermGen: 9678K->9675K(21504K)], 0.3152834 secs] [Times: user=0.39 sys=0.00, real=0.32 secs] [Full GC [PSYoungGen: 8192K->3583K(9216K)] [ParOldGen: 8418K->9508K(10240K)] 16610K->13092K(19456K) [PSPermGen: 9675K->9675K(22016K)], 0.1913859 secs] [Times: user=0.34 sys=0.00, real=0.19 secs] [Full GC [PSYoungGen: 7716K->7702K(9216K)] [ParOldGen: 9508K->9508K(10240K)] 17224K->17210K(19456K) [PSPermGen: 9675K->9675K(21504K)], 0.2769775 secs] [Times: user=0.52 sys=0.00, real=0.28 secs] [Full GC [PSYoungGen: 7702K->7702K(9216K)] [ParOldGen: 9508K->9409K(10240K)] 17210K->17111K(19456K) [PSPermGen: 9675K->9675K(21504K)], 0.2491993 secs] [Times: user=0.64 sys=0.00, real=0.25 secs]“[GC”和“[full DC”说明了这次垃圾回收的停顿类型。如果是调用System.gc()方法所触发的收集,那么这里显示“[Full DC(System)”.