JVM虚拟机垃圾收集器

一、概述

        前面讲解了JVM的垃圾收集算法,JVM内存分为新生代和老年代,新生代对象存活周期短,GC非常频繁,一般被称为Minor GC;而老年代对象存活的时间比较长,一般被称为Major GC;Major GC速度一般比Minor GC速度慢10倍以上。

垃圾收集器组合

            JVM虚拟机垃圾收集器

        新生代收集器:Serial、ParNew、Parallel Scavenge;

        老年代收集器:Serial Old、Parallel Old、CMS;

        整堆收集器:G1;

并行与并发概念

并行:指多个垃圾收集器同时工作,但是此时用户线程仍在处于等待的状态。

并发:指垃圾收集线程和用户的线程同时执行。

二、垃圾收集器介绍

Stop The World概念:JVM在后台自动发起和自动完成的,在用户不可见的情况下,当进行垃圾回收的时候,把用户正常的工作线程全部停掉,即GC停顿;

(1)Serial收集器

单线程收集器。

特点:复制算法、单线程、新生代

优点:简单高效, 对于限定单个CPU的环境来说,Serial收集器没有线程交互(切换)开销,可以获得最高的单线程收集效率;

缺点:进行垃圾收集时必须暂停所有工作线程会“Stop The World”

应用场景:HotSpot在Client模式下默认的新生代收集器,在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的.

 Serial/Serial Old组合收集器运行示意图如下:

JVM虚拟机垃圾收集器

(2)ParNew收集器

ParNew收集器是Serial收集器的多线程版本。

特点:复制算法、多线程(并行收集)、新生代

缺点:进行垃圾收集时必须暂停所有工作线程会“Stop The World”

应用场景: 在Server模式下,ParNew收集器是一个非常重要的收集器,因为除Serial外,目前只有它能与CMS收集器配合工作;但在单个CPU环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销。

只有ParNew能与CMS收集器配合:因为Parallel Scavenge(以及G1)都没有使用传统的GC收集器代码框架,而另外独立实现;而其余几种收集器则共用了部分的框架代码;

JVM虚拟机垃圾收集器

(3)Parallel Scavenge收集器

吞吐量(Throughput)是垃圾收集时用户线程的停顿时间。

吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

Parallel Scavenge垃圾收集器因为与吞吐量关系密切,也称为吞吐量收集器(Throughput Collector)。

特点:复制算法、多线程收集(并行),新生代

优点:可以控制吞吐量

缺点:会Stop The World

应用场景:高吞吐量为目标,即减少垃圾收集时间,让用户代码获得更长的运行时间;当应用程序运行在具有多个CPU上,对暂停时间没有特别高的要求时,即程序主要在后台进行计算,而不需要与用户进行太多交互;

(4)Serial Old收集器

Serial收集器的老年代版本;

特点:标记-整理算法、单线程、老年代

优点:效率高

缺点:会Stop The World

应用场景:主要用于Client模式;

而在Server模式有两大用途:
      (A)、在JDK1.5及之前,与Parallel Scavenge收集器搭配使用(JDK1.6有Parallel Old收集器可搭配);
      (B)、作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用(后面详解);

Serial/Serial Old收集器运行示意图如下:

JVM虚拟机垃圾收集器

(5)Parallel Old收集器

Parallel Scavenge收集器的老年代版本

特点:标记-整理、多线程收集(并行)、老年代

应用场景:JDK1.6及之后用来代替老年代的Serial Old收集器,特别是在Server模式,多CPU的情况下,这样在注重吞吐量以及CPU资源敏感的场景,就有了Parallel Scavenge加Parallel Old收集器的"给力"应用组合。

Parallel Scavenge/Parallel Old收集器运行示意图如下:

JVM虚拟机垃圾收集器

(6)CMS收集器

是一种获取最短回收停顿时间为目标的收集器。

整个过程分为四步:初始标记、并发标记、重新标记、并发清除

初始标记、重新标记两个步骤仍然需要“Stop The World”

优点:并发收集、低停顿、以获取最短回收停顿时间为目标

缺点:

  • 对CPU资源非常敏感, 并发收集虽然不会暂停用户线程,但因为占用一部分CPU资源,还是会导致应用程序变慢,总吞吐量降低
  • 无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败   
  • 产生内存碎片

(7)G1收集器

常规的垃圾收集器(串行,并行,CMS)都将堆结构分为三个部分:年轻代,老年代和固定大小的永久代。

JVM虚拟机垃圾收集器

G1将堆被分成一组大小相等的区域,每个是连续范围的虚拟内存。某些Regions被分配给和常规收集器一样的角色(eden区,survivor区,老年代),但他们没有固定的大小。这提供了更大的内存使用灵活性。

JVM虚拟机垃圾收集器

在执行垃圾收集时,G1以类似于CMS收集器的方式运行。G1执行并发的全局标记阶段来确定整个堆中对象的活动性。标记阶段完成后,G1知道哪些区域大部分是空的。它首先收集这些区域,这通常产生大量的可用空间。这就是为什么这种方式叫做垃圾收集优先。顾名思义,G1将其收集和压缩活动集中在可能充满可回收对象的堆区域,也就是垃圾。G1使用暂停预测模型来满足用户定义的目标暂停时间,并根据指定的目标暂停时间选择要收集的区域数量。

被G1标识成熟的区域是通过转移的方式收集。G1将对象从堆的一个或多个区域复制到堆上的单个区域,并且在此过程中,同时压缩和释放内存。这种转移方法在并行运行在多处理器上,以减少暂停时间并提高吞吐量。因而,对于每一次垃圾收集,G1都不断地减少碎片,并且在用户定义的暂停时间内工作。这种方式超出了以前的两种方法(指CMS和ParallelOld)的能力。CMS垃圾收集器不执行内存压缩,ParallelOld垃圾收集器执行全堆压缩,这将导致很大的暂停时间。

一个值得注意的点,G1不是一个实时垃圾收集器。它尽可能的符合设定的目标暂停时间,但是不能绝对实现。根据以前收集的垃圾时间,G1估计可以在用户指定的目标时间内收集多少个区域。因此,收集器具有收集区域的成本的相当准确的模型,并且使用该模型来确定目标暂停时间内收集哪些区域和多少区域。

注意:G1同时有并发(与应用程序线程一起运行,例如细化,标记,清理)和并行(多线程,例如STW)的阶段。FullGC仍然是单线程的,但是如果您的应用程序正确调优,应避免使用Full GC。

特点:

        并发与并行:能充分利用多CPU、多核环境下的硬件优势、可以并行来缩短"Stop The World"停顿时间、 也可以并发让垃圾收集与用户程序同时进行;

        分代收集,收集范围包括新生代和老年代  :能独立管理整个GC堆(新生代和老年代),而不需要与其他收集器搭配,能够采用不同方式处理不同时期的对象;

        结合多种垃圾收集算法,空间整合,不产生碎片:局部看是复制算法,总体看是标记-整理算法。

        可预测的停顿:低停顿的同时实现高吞吐量:G1除了追求低停顿处,还能建立可预测的停顿时间模型、 可以明确指定M毫秒时间片内,垃圾收集消耗的时间不超过N毫秒;

应用场景:  面向服务端应用,针对具有大内存、多处理器的机器,最主要的应用是为需要低GC延迟,并具有大堆的应用程序提供解决方案; 如:在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒;

参考资料:

深入理解Java虚拟机——JVM高级特性与最佳实践(第2版).

https://blog.****.net/tjiyu/article/details/53983650