垃圾收集器算法
Throughtput收集器是一款关注吞吐量的收集器。这个收集器也是惟一一个实现了UseAdaptiveSizePolicy策略的垃圾收集器。容许用户经过指定最大的暂停时间和垃圾收集器所占用的时间百分比,而后动态调整JVM的参数来达到配置的目标。多线程
上图是一个经典的垃圾收集器的图,图中有颜色的就是 throughput垃圾回收器 ,各个线表明的是各个垃圾回收器之间哪两个能够配合使用。并发
从上图能够看出 Parralel Scanvenge垃圾回收器不能和CMS配合使用。框架
ParallelScavenge收集器是新生代收集器,使用的是Scavenge GC。是一个并行收集器。在copping阶段能够多个线程一块儿执行,在多线程的场景下可一尽可能的提升Minor GC的效率。目的是能够达到一个可控的吞吐量。 性能
吞吐量 = 运行用户代码的时间/(运行用户代码时间+垃圾收集时间)测试 |
虚拟机运行总时间100分钟,其中垃圾收集器运行了1分钟,则吞吐量就是99%spa
ParallelScavenge收集器的来历为,在HotSpot VM开发的时候都是在分代式框架下开发,而且但愿第三方开发者也能在这个框架下开发自定义的收集器,这样就能和其余收集器配合使用。可是有个开发者不肯意使用这个框架,而且凭借本身的能力开发了并行收集器,这时候JVM中的并行收集器是不存在的。通过测试,这个收集器的性能仍是很是不错的,因而就被放入到了HotSopt中成为了ParallelScavenge收集器。这就是为何这个收集器不能和CMS配合使用,由于它就不是在分代式框架下开发的。线程
ParallelScavenge是在jdk1.7以前的默认垃圾回收器。使用ParallelScavence收集器须要须要关注如下两个参数:设计
这个参数控制GC最大的停顿时间。设置之后经过动态调整新生代的大小来达到暂停时间是能够控制的。可是这个值不是越小越好。由于这个若是这个值设置的比较小,那一定会致使新生代的比较小,新生代空间比较小的话,会致使更加频繁的minor GC,这样总间隔时间就会变大。日志
收集器运行时间所占时间的比率,介于0到100的整数。
经过调整这两个参数的大小能起到动态调整吞吐量和暂停时间的目的,这样用户不用关心新老年代应该各自设置多大,只须要设置好这两个值,剩下的交给虚拟机动态调整。
Parallel Old是ParallelScavenge的老年代版本,以前若是新生代使用ParallelScavenge,老年代只能使用Serial Old,为了弥补这个缺失,因此在jdk 1.6的时候开发了Parallel Old 老年代并行垃圾回收器,配合ParallelScavenge使用。此时二者双剑合璧,才更能显现出来Throughtput的强悍之处
单线程老年代收集器,主要用在client模式下,不过也做为CMS垃圾收集器并发模式失效之后备用收集器。
Throughtput收集器配置
Throughtput收集器经过第一节的图中能够看出有两种配置
-XX:+UseParallelGC
或者
-XX:+UseParallelOldGC
,这两个配置任选一个,就会选中ParallelScavenge+Parallel Old组合做为收集器。
打印的GC日志以下
[Full GC (System.gc()) [PSYoungGen: 992K->0K(29696K)] [ParOldGen: 8K->761K(68608K)] 1000K->761K(98304K), [Metaspace: 3152K->3152K(1056768K)], 0.0060131 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
若是非得强制使用单线程老年代收集器(Serial Old)能够以下配置:
-XX:+UseParallelGC -XX:-UserParallelOldGC
发生GC时,打印的日志以下
[Full GC (System.gc()) [PSYoungGen: 928K->0K(29696K)] [PSOldGen: 8K->767K(68608K)] 936K->767K(98304K), [Metaspace: 3167K->3167K(1056768K)], 0.0023446 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
ParallelScavenge和ParNew
在收集器的图中,咱们看到还有一个ParNew的新生代收集器,因为CMS收集器不能配合ParallelScavenge使用,因此只剩下一个单线程的Serial收集器,为了可以有所匹配,因此出来了并行的新生代收集器,它和ParallelScavenge相比有以下不一样:
若是是关注吞吐量的应用,采用Throughput收集器是个不错的选择。而且能够经过设置
-XX:ParallelGCThreads=N 来设置并行GC线程数。在使用的过程当中最好不要手工的指定新生代和老年代的大小,而是指定MaxGCPauseMills 和GCTimeRatio让其自动调整,以达到最优值。同时设置咱们堆大小便可。
CMS收集器设计的初衷是了消除Throughtput收集器和Serial收集器FullGC周期的长时间停顿。CMD收集器在Minor GC时会暂停全部应用线程,而且以多线程的方式进行垃圾回收。
CMS收集器在FullGC时再也不暂停应用线程,而是使用若干个后台线程按期的对老年代空间进行扫描,及时会后其中再也不使用的对象。这种作法使得CMS成为一个低延迟的收集器。应用线程只在Minor GC以及后台线程骚烤老年代时发生极其短暂的停顿。应用程序线程停顿的总时长与使用Throughtput收集器比起来短的多。
可是会付出额外的代价,那就是更高的CPU使用:必须有足够的CPU资源用于后台运行垃圾收集线程。除此以外,后台再也不进行压缩整理工做,也就是说堆回逐渐的碎片化。若是CMS的后台线程没法得到完成他们任务所须要的CPU资源,或者若是堆变的过分碎片化以致于没法找到连续内存分配先对象,CMS就会蜕化为Serial收集器的行为,暂停全部应用线程,使用单线程进行回收,整理老年代空间,以后又恢复到并发运行,再次启动后台线程,直到堆变的再次过分碎片化。
开启标志:
-XX:+UseConcMarkSweepGC ,-XX:+UseParNewGC
这两个标志能够开启CMS垃圾回收器。