# 垃圾收集器 Uncompleted

垃圾回收器是内存回收的具体体现。Java虚拟机中对垃圾收集器应该如何实现是没有任何固定的规定的,所有不同厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大的差别。

HotSpot虚拟机的垃圾收集器

如上图所示,展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明可以搭配使用。处于上面区域的是新生代收集器,下面区域的是老年代收集器。

# Serial收集器

Serial收集器是最基本、历史最久的收集器,曾经是JDK1.3.1版本之前的虚拟机新生代收集的唯一选择。这个收集器是一个单线程的收集器,这意味着它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,同时,在它进行垃圾收集的时候,它必须暂停其它所有的工程线程,直到它收集结束

Serial/Serial Old收集器运行示意图

当然,它也是有优点的:简单而高效(与其他垃圾收集器的单线程相比),对于限定了单个CPU的环境来说,Serial收集器由于没有线程之间监护的开销,专心从事垃圾收集工作,自然就会有更高的单线程收集效率。所以,它依然是虚拟机运行在Client模式下的默认新生代收集器

# ParNew收集器

ParNew收集器其实是Serial收集器的多线程版本。ParNew除了使用多线程进行垃圾收集之外,其余行为还有Serial收集器可用的所有控制参数、收集算法、对象分配规则、回收策略等。

ParNew收集器是许多运行在Server模式下的虚拟机中首选的新生代收集器,因为目前,除了Serial收集器之外,只有它可以与CMS收集器相互配合。而CMS收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户工作线程同时工作,具有划时代的意义。

ParNew收集器在单CPU的环境中的运行效果不会比Serial收集器更好,但是随着使用的CPU数量的增加,它对GC的系统资源的有效利用还是有很多好处的。它默认开启的收集线程数与CPU的数量相同,如果CPU数量飞铲过,就可以使用-XX:ParallelGCThreads;参数来限制垃圾收集的线程数。

ParNew/Serial Old收集器运行示意图

除此之外,我们需要理解两个概念:

  • 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态;
  • 并发(Concurrent):指用户线程与垃圾收集线程同时执行(不一定是并行,也可以是交替执行),但用户程序的确是在继续执行,而垃圾收集程序运行在另一个CPU上。

# Parallel Scavenge收集器

Parallel Scavenge收集器是一个新生代收集器,也是同样使用复制算法,也是并行多线程的收集器,但它的关注点是达到一个可控制的吞吐量(Throughput)。所以,Parallel Scavenge收集器也被称为吞吐量优先收集器。

吞吐量就是CPU用于运行用户代码的时间与CPU消耗时间的比值,即吞吐量=运行用户代码时间运行用户代码时间+垃圾收集时间吞吐量=\frac{运行用户代码时间}{运行用户代码时间 + 垃圾收集时间}

高吞吐量可以高效率地利用CPU时间,尽快完成程序的运算任务,适合在后台运算不需要太多交互的任务

# Serial Old收集器

Serial收集器的老年代版本,是单线程的,使用标记-整理算法,也是主要提供给Client模式下的虚拟机使用的。

# Parallel Old收集器

Parallel收集器的老年代版本,是多线程的,采用标记-整理算法,同样是注重吞吐量。

# CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。当一些应用十分重视服务的响应速度,希望系统停顿时间最短的话,CMS收集器就符合这类应用的需求。

CMS收集器是基于标记——清除算法实现的,它的运作过程相比其它的收集器更发咋一些,分为4个步骤,包括:

  • 初始标记(CMS inital mark)
  • 并发标记(CMS concurrent mark)
  • 重新标记(CMS remark)
  • 并发清除(CMS concurrent sweep)

# G1收集器

即Garbage First收集器,是一个里程碑的收集器,开创了面向局部收集的思路和基于Region的内存布局形式。在延迟可控的情况下,可以获得尽可能高的吞吐量。

G1收集器可以将连续的Java堆划分为多个大小相等的独立区域,每一个Region都可以根据需要扮演新生代的Eden空间,Survivor空间或者老年空间。

收集过程也是4个步骤:

  • 初始标记:标记GC Roots能够直接关联到的对象
  • 并发标记:并发进行可达性分析
  • 最终标记:短暂停顿,处理并发标记结束时遗留的少量对象
  • 筛选回收:更新Region统计数据,根据价值和回收成本机型排序,并依据用户期望的停顿时间来制定回收计划。

所以,Java8以前是Parallel GC,Java9以后改为G1 GC

G1收集器具有以下特点:

  • 并行与并发:G1能够充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿的时间。
  • 分代收集:与其他收集器一样,分代概念在G1中依然得以保留。
  • 空间整合:与CMS的「标记-清理」算法不同,G1从整体来看是基于「标记-整理」算法实现的收集器,从局部来看,则是基于「复制」算法来实现的。
  • 可预测的停顿:这个G1相对于CMS的另外一个优势,G1除了能够降低停顿时间之外,还可以建立可预测的停顿时间模型,能够让使用者明确指定在一个长度为M毫秒的时间片段内。