如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

虽然我们在对各种收集器进行比较,但是并非为了挑出一个最好的收集器。因为直到现在为止还没有最好的收集器出现,更加没有万能的收集器,所以我们选择的只是对具体应用最合适的收集器。

1.Serial收集器(串行收集器)

这个收集器是一个单线程的收集器,但是它的单线程的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的线程(Stop-The-World:将用户正常工作的线程全部暂停掉),直到它收集结束。收集器的运行过程如下图所示:

Java垃圾收集器_老年代

上图中:

新生代采用复制算法,Stop-The-World

老年代采用标记-整理算法:Stop-The-World

当他进行GC工作的时候,虽然会造成Stop-The-World,但是它存在有存在的原因:正是因为他的简单而高效(与其他收集器的单线程比),对于限定单个CPU的环境来说,没有现成交互的开始,专心做GC,自然可以获得最高的单线程收集效率。所以Serial收集器对于运行在client模式下是一个很好的选择(它依然是虚拟机运行在client模式下的默认新生代收集器)。

 

2.ParNew收集器

Serial收集器的多线程版本(使用多条线程进行GC)

它是运行在server模式下的首选新生代收集器,除了Serial收集器外,目前只有它能与CMS收集器配合工作。CMS收集器是一个被认为具有时代意义的并发收集器,因此如果有一个垃圾收集器能和它配合一起使用更加完美,那这个收集器必然也是一个不可或缺的部分了。收集器的运行过程如下图所示:

Java垃圾收集器_单线程_02

上图中:

新生代采用复制算法:Stop-The-World

老年代采用标记-整理算法:Stop-The-World

 

3.Parallel Scavenge收集器

类似ParNew,但更加关注吞吐量。目标是:达到一个可控制吞吐量的收集器。

停顿时间和吞吐量不可能同时调优。我们一方面希望停顿时间少,另一方面希望吞吐量高。其实这是矛盾的,因为:在GC的时候,垃圾回收的工作总量是不变的,如果将停顿时间减少,那么频率就会提高;频率提高说明会频繁的进行GC,那吞吐量就会减少,性能就会降低。

吞吐量:CPU用于用户代码的时间/CPU总消耗时间的比值。即=运行用户代码的时间/(运行用户代码时间+垃圾收集时间)。比如,虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%

4.G1收集器

是当今收集器发展的最前沿成果之一,直到JDK1.7,SUN公司才认为它达到了足够成熟的商用程度。

优点:

它最大的优点是结合了空间整合,不会产生大量的碎片,也降低了进行GC的频率。

二是可以让使用者明确指定停顿时间,(可以指定一个最小时间,超过这个时间,就不会进行回收了)

它有了这么高效率的原因之一就是:对垃圾回收进行了划分优先级的操作,这种有优先级的区域回收方式保证了它的高效率。

如果你的应用追求停顿,那G1现在已经可以作为一个可以尝试的选择,如果你的应用追求吞吐量,那G1并不会为你带来什么特别的好处。

注意:以上所有的收集器当中,当执行GC是,都会Stop-The-World,但是下面的CMS收集器却不会这样。

 

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

CMS收集器(Concurrent Mark Sweep:并发标记清除)是一种以获取最短回收停顿时间为目标的收集器。适合应用在互联网站或者B/S系统的服务器上,这类应用尤其总是服务器的响应速度,希望系统停顿时间最短。

CMS收集器运行过程:(着重实现了标记的过程)

(1)初始标记

根可以直接关联到对象

速度快

(2)并发标记(和用户线程一起)

主要标记过程,标记全部对象

(3)重新标记

由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正。

(4)并发清除(和用户线程一起)

整个过程如下图所示:

Java垃圾收集器_单线程_03

上图中,出现标记和重新标记时,需要Stop-The-world.整个过程中耗时最长的是并发标记和并发清除,这两个过程都可以和用户线程一起工作。

优点:

并发收集,低停顿。

缺点:

(1)导致用户执行速度降低。

(2)无法处理浮动垃圾,因为它采用的是标记-清除算法,有可能有些垃圾在标记之后,需要等到下一次GC才会被回收。如果CMS运行期间无法满足程序需要,那么就会临时启用Serial Old收集器来重新进行老年代的收集。

(3)由于采用的是标记-清除算法,那么就会产生大量的碎片。往往会出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前出发一次Full GC

 

疑问:既然标记-清除算法会造成内存空间的碎片化,CMS收集器为什么使用标记清除算法而不是标记整理算法?

答:CMS收集器更加关注停顿,它做GC的时候是和用户线程一起工作的(并发执行),如果使用标记整理算法的话,那么清理的时候就会去移动可用对象的内存空间,那么应用程序的线程就很有可能找不到应用对象在哪里。

6.Serial Old收集器

Serial Old是Serial收集器的老年代版本,使用“标记-整理”算法。这个收集器的主要意义也是在于给Client模式下的虚拟机使用。如果在Server模式下,那么它主要还有两大用途:一种用途是在JDK1.5以及之前的版本中与Parallel Scavenge收集器搭配使用。另一种用途就是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。

7.Parallel Old收集器

 

心再坚强也不要独自飞翔