JVM垃圾收集器

虚拟机垃圾收集器

概览


以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。

  • 单线程与多线程:单线程指的是垃圾收集器只使用一个线程进行收集,而多线程使用多个线程
  • 串行与并行:串行指的是垃圾收集器与用户程序交替执行,这意味着在执行垃圾收集的时候需要停顿用户程序;并行指的是垃圾收集器和用户程序同时执行
    • 除了 CMSG1 之外,其它垃圾收集器都是以串行的方式执行

1. Serial 收集器(单线程、复制算法)


Serial 收集器是最基本垃圾收集器。

  • 新生代
  • 单线程
    • 只会使用一条线程去完成垃圾收集工作
    • 在进行垃圾收集的同时,必须暂停其他所有的工作线程,直到垃圾收集结束
  • 复制算法

特点
它的优点是简单高效,对于单个 CPU 环境来说,由于没有线程交互的开销,因此拥有最高的单线程收集效率,所以依然是 java 虚拟机运行在 Client 模式下默认的新生代垃圾收集器。

2. ParNew 收集器


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

  • 新生代
  • 多线程
    • 除了使用多线程进行垃圾收集之外,其余的行为和 Serial 收集器完全一样
    • 在垃圾收集过程中同样要暂停所有其他的工作线程
  • 复制算法

特点
它是 Server 模式下的虚拟机首选新生代收集器,除了性能原因外,主要是因为除了Serial 收集器,只有它能与 CMS 收集器配合工作。

3. Parallel Scavenge 收集器

它与 ParNew 一样是多线程收集器。

  • 新生代
  • 多线程
  • 复制算法

特点

  • 其它收集器目标是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,因此它被称为“吞吐量优先”收集器
    • 吞吐量(Thoughput):CPU 用于运行用户代码的时间/CPU 总消耗时间,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
  • 适合在后台运算而不需要太多交互的任务
    • 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。 而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务
  • 自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个重要区别
    • 打开自适应的调节策略,就不需要手工指定新生代的大小、Eden 和 Survivor 区的比例、晋升老年代对象年龄等细节参数。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量

4. Serial Old 收集器


它是 Serial 收集器的老年代版本,也是给 Client 场景下的虚拟机使用。

  • 老年代
  • 单线程
  • 标记-整理算法

特点
在Server 模式下有两大用途:

  • 在 JDK 1.5 以及之前版本(Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用
  • 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用

5. Parallel Old 收集器


它是 Parallel Scavenge 收集器的老年代版本。

  • 老年代
  • 多线程
  • 标记-整理算法

特点
在注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge + Parallel Old 收集器。

6. CMS 收集器


CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,可以为交互比较高的程序提高用户体验。

  • 老年代
  • 多线程
  • 标记-清除算法

特点
CMS收集器是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。整个过程分为四个步骤:

  1. 初始标记:仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿
  2. 并发标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿
  3. 重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿
  4. 并发清除:不需要停顿

缺点:

  • 吞吐量低:低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率不够高
  • 无法处理浮动垃圾,可能出现 Concurrent Mode Failure
    • 浮动垃圾是指并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS
  • 标记-清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC

7. G1 收集器


G1(Garbage-First)是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征。

  • 新生代/老年代
  • 多线程
  • 标记-整理算法

特点

  • 并行与并发
    • G1 能充分利用多核环境下的硬件优势,使用多个 CPU 来缩短 Stop-The-World 停顿时间。部分其他收集器原本需要停顿 Java 线程执行的 GC 动作,G1 收集器仍然可以通过并发的方式让 java 程序继续执行
  • 分代收集
    • 虽然 G1 可以不需要其他收集器配合就能独立管理整个 GC 堆,但是还是保留了分代的概念
  • 空间整合
    • 与 CMS 的“标记-清理”算法不同,G1 从整体来看是基于“标记-整理”算法实现的收集器
    • 从局部上来看是基于“标记-复制”算法实现的
  • 可预测的停顿
    • 能让使用者明确指定在一个长度为 M 毫秒的时间片段内,消耗在 GC 上的时间不得超过 N 毫秒

Region

G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。

堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。

G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。

  • 通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能
  • 通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region
posted @ 2021-03-30 18:03  当康  阅读(127)  评论(0编辑  收藏  举报