垃圾收集器

来源:互联网 发布:围棋记谱软件安卓版 编辑:程序博客网 时间:2024/06/06 01:52

如果说垃圾收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。Java虚拟机规范中对垃圾收集器应该如何实现没有任何规定,因此不同厂商,不同版本的虚拟机所提供的垃圾收集器都可能会有很大的差别,并且一般都会提供参数供用户根据自己的应用特定和要求进行组合出各个年代所使用的收集器。这里所讨论的收集器是基于Sun HotSpot虚拟机1.6版Update22,这个虚拟机所包含的收集器如下所示:
这里写图片描述
上图展示了七中作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。
下面简要介绍这些垃圾收集器。

1. Serial收集器

Serial收集器是最基本、历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新生代收集的唯一选择。大家看名字就知道,这个收集器是一个单线程的收集器,但是它的“单线程”的意义并不仅仅是说明它只会使用一个Cpu或者一个收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程(Sun将这件事情称之为“stop the world”),直到它收集结束。“Stop the world”听上去有点酷,这项工作实际上是由虚拟机在后台自动发起和自动完成的,在用户不可见的情况下把用户的正常工作的线程全部停掉,这对很多应用来说都是难以接受的。
Serial /Serial Old收集器运行示意图如下(注意是只有一个线程在收集):
这里写图片描述
Serial收集器的优点在于:简单而高效,对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾回收,可以获得很高的单线程收集效率。在用户的桌面应用场景中,分配给虚拟机管理的内存一般来说不会很大。收集几十兆甚至一两百兆的新生代,停顿时间完全可以控制在几十毫秒最多一百多毫秒以内,只要不是频繁发生,这点停顿是可以接受的。

2. ParNew收集器

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾手机之外,其余行为包括Serial收集器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold等)、收集算法、Stop the World、对象分配规则、回收策略等都与Serial收集器完全一样,实现上这两种收集器也共用了相当多的代码。
ParNew收集器的工作过程如下所示:
这里写图片描述
ParNew用的也比较多,因为只有Serial或者ParNew才能与CMS一起工作。

3. Serial Old收集器

Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用“标记-整理”算法,这个收集器的主要意义也是被Client模式下的虚拟机使用。如果在Server模式下,它主要还有两大用途:一个是在JDK1.5之前的版本中与Parallel Scavenge收集器搭配使用。另外一个就是作为CMS收集器的后备方案,在并发收集发生错误的时候使用。
Serial Old示意图如下:
这里写图片描述

4. CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获得最短回收停顿时间为目标的收集器。目前很大一部分的Java应用程序都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
从名字上看(包含“Mark Sweep”),就可以看出CMS收集器是基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程划分为四个步骤:
1) 初始标记(CMS initial mark)
2) 并发标记(CMS concurrent mark)
3) 重新标记(CMS remark)
4) 并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤仍然需要“stop the world”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Root Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行的。CMS示意图如下:
这里写图片描述
CMS是一款优秀的收集器,它的主要优点在名字上已经体现出来了:并发收集、低停顿。但是CMS也有一些缺点:
1)CMS收集器对CPU资源非常敏感。其实面向并发设计的程序对CPU资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量降低。
2)CMS是基于“标记-清除”算法实现的收集器,会产生大量碎片。

5. G1收集器

G1收集器是垃圾收集理论进一步发展的产物,它与前面的CMS收集器相比有两个显著的改进:一个是G1收集器是基于“标记-整理”算法实现的收集器,也就是说它不会产生空间碎片,这对于长时间运行的应用系统来说非常重要;二是它可以非常精确地控制停顿,既能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java的垃圾收集器的特征了。
G1收集器可以实现在基本不牺牲吞吐量的前提下完成低停顿的内存回收,这是由于它能够极力避免区域的垃圾收集,之前的垃圾收集进行收集的范围都是整个新生代或者老年代,而G1将整个Java堆(包括新生代、老年代)划分为多个大小固定的独立区域(Region),并且跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域(这就是Garbage First名称的由来)。区域划分以及有优先级的区域回收,保证了G1回收器在有限的时间内可以获得最高的垃圾收集效率。

参考《深入理解Jvm虚拟机》

0 0
原创粉丝点击