JVM探秘4---垃圾收集器介绍

Java虚拟机有不少垃圾收集器算法

下面先来了解HotSpot虚拟机中的7种垃圾收集器:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1,先介绍一些垃圾收集的相关概念,再介绍它们的主要特色、应用场景、以及一些设置参数和基本运行原理。多线程

常见的垃圾收集器关系图以下:并发

若是两个收集器直接有连线,则表示能够搭配使用,而G1收集器是不区分老年代和新生代的,因此不须要和其余收集器搭配,其余的则只能用于老年代或是新生代。jvm

下面针对每一个收集器逐个分析:性能

1.Serial收集器(新生代收集器)

Serial是历史最悠久的收集器,也一个单线程收集器,只有一个CPU或一个线程来完成垃圾收集工做,并且Serial收集器在垃圾回收的时候会暂停全部工做线程,直到垃圾回收结束再恢复工做线程。优化

2.ParNew收集器(新生代收集器)

ParNew收集器是Serial收集器的多线程版本,工做方式和工做原理彻底一致,只是ParNew收集器会建立多个线程来进行垃圾回收工做。不过若是是在单CPU的状况下,ParNew收集器的性能反而不必定有Serial收集器好,由于ParNew还有额外的线程之间切换的消耗,若是是多CPU的状况下,则效果更好点,因此ParNew默认开启的垃圾收集的线程个数一个和CPU的数量是1:1的比例,在线程数比CPU数量小的状况下,ParNew的性能仍是很可观的。线程

3.Parallel Scavenge收集器(新生代收集器)

Parallel Scavenage收集器是采用了复制算法,且是并行的多线程收集器,它的特色是不关注收集器用户线程的停顿时间,而是关注达到一个可控制的吞吐量。吞吐量为CPU用于运行用户线程的代码与CPU总耗时的比例,好比JVM工做100分钟,垃圾回收使用1分钟,用户线程使用99分钟,则吞吐量就是99%,Paramllel Scavenge收集器提供两个参数用户控制吞吐量。分别是控制最大垃圾收集停顿时间 -XX:MaxGCPauseMillis参数、设置吞吐量大小-XX:GCTimeRatio对象

若是设置停顿时间太短,则垃圾收集时花费的时间不会超过最大值,可是若是停顿时间过于小,就会致使新生代的垃圾回收的频率会增高,原本能够10秒收集一次,停顿100毫秒,变成了5秒收集一次,每次停顿70毫秒,虽然停顿时间下降了,可是总体的吞吐量却降低了。blog

而若是直接设置吞吐量,则收集器会按照吞吐量设置的值来分配总体的垃圾收集的时间来进行收集垃圾。递归

4.Serial Old收集器(老年代收集器)

Serial Old是Serial收集器的老年代版本,也是单线程的,使用的“标记-整理”算法

5.Parallel Old收集器(老年代收集器)

Parallel Old是Paraller Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法,只能与Parallel Scavenge收集器搭配使用

6.CMS收集器(老年代收集器)

CMS是目前最经常使用的收集器,主要是和ParNew来搭配使用。CMS(Concurrent  Mark Sweep)从名字能够看出是并发的标记清除垃圾收集器,过程比较复杂。特色是以获取最短回收停顿时间为目标,整个过程大体分为四个步骤:

初始标记-》并发标记-》并发预处理-》从新标记-》并发清除

初始标记:标记一下GC Roots可以关联到的对象,速度很快,可是也会使用户线程短暂的中止,只是停顿的时间很快。

并发标记:并发标记耗时较长,可是能够和用户线程并发进行,不须要使用户暂停,不过会消耗CPU的资源,会影响到用户线程的吞吐量,CMS默认会开启回收线程的数量是CPU个数+3/4,好比cpu是1的状况下,会启动一个线程,若是cpu是5的话,就会启动2个线程,并发标记会根据初始标记出来的经过GC ROOTS关联到的对象,而后经过递归继续标记这些对象能够达到的对象

从新标记:暂停用户线程,从新在堆中进行可达性分析,标记存货对象,此时的存活又没有被标记的对象不多了,因此用户线程停顿的时间也较短

并发清除:和用户线程并发进行,清除没有被标记的对象

另外CMS收集器没法处理浮动垃圾,由于cms和用户线程是并发进行的,在垃圾回收的同时用户线程可能会产生新的垃圾,这就使得本次垃圾回收没法清除,会留到下一次回收。另外cms是和用户线程并行处理的,因此在工做时还须要预留足够的内存空间在用户线程使用,所以cms收集器不能像其余收集器同样等到老年代几乎满了才开始进行垃圾回收,须要预留一部分给用户线程使用,默认状况下在老年代使用了68%空间以后就会触发垃圾回收。固然也能够经过设置jvm参数-XX:CMSInitatingOccupancyFraction来设置触发的百分比。

而若是CMS没有预留足够空间给用户线程的话,会出现“Concurrent Mode Failure”失败,这是虚拟机就会启动预备方案,临时启用Serial Old收集器来从新对老年代进行一次垃圾收集,这样就会影响性能。

并且因为CMS是经过标记清除算法,因此会产生大量的内存碎片,就会出现老年代内存空间足够可是没法建立一些大对象,就会提早触发一次Full GC。而CMS就提供了两个JVM参数用来优化这个问题,分别是:

-XX:+UseCMSCompactAtFullCollect参数,使得在实现Full GC以后额外进行一次内存整理,这样就没有了内存碎片,可是涉及到内存整理,因此停顿时间变长了

-XX:CMSFullGCsBeforeCompaction参数,设置在执行多少次不压缩的Full GC以后进行一次内存整理。

7.G1收集器  (新生代、老年代收集器)

G1收集器没有新生代和老年代的区分,G1实现了不牺牲吞吐量的状况下又达到了低停顿的效果。主要是由于G1不像其余收集器同样针对整个新生代或是老年代进行垃圾回收,并且将整个堆内存划分红了多个大小同样的独立区域,并跟踪每一个区域的垃圾状况,而且有一个优先列表,优先回收垃圾最多的区域。

相关文章
相关标签/搜索