Java垃圾收集器


《Offer来了-Java基础篇》第1.8章

1.8垃圾收集器

1
2
3
4
5
6
7
8
9
10
11
12
13
graph LR
subgraph 新生代
n(新生代)---1(Serial:单线程复制算法)
n---2(ParNew:多线程复制算法)
n---3(Parallel Scavenge:多线程复制算法)
end

subgraph 老年代
老年代---CMS(CMS:多线程标记清除算法)
老年代---SO(Serial Old:单线程标记整理算法)
老年代---PO(Parallel Old:多线程标记整理算法)
老年代---GI(GI:多线程表标记整理算法)
end

1.8.1 Serial收集器

单线程

停止所有其他线程,Stop The World(Dio表示很赞,砸瓦鲁多),只启用GC线程。

  • 新生代:复制算法
  • 老年代:标记-整理算法

 Serial 收集器

  • 优点:没有线程交互开销,简单而高效
  • 缺点:体验太差了。。。
  • 是JVM在Client模式下新生代的默认收集器

1.8.2 ParNew收集器

多线程版本的Serial收集器

  • 新生代:复制算法
  • 老年代:标记-整理算法

ParNew 收集器

  • 也会暂停其他所有线程
  • 是JVM在Server模式下新生代的默认收集器
  • 除了 Serial 收集器外,只有它能与 CMS 收集器(真正意义上的并发收集器,后面会介绍到)配合工作

并行和并发概念补充:

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

这里补充的是说GC和用户线程的并行并发(这里说的有点模糊,没太搞清):

  • 并行:GC并行,用户暂停;
  • 并发:GC与用户同时发生,可能交替执行;

操作系统/线程里的并行并发是如下:

并行与并发

并行(Parallel):同时做,不暂停。打个比方,一边吃饭一边打电话,你真行。

并发(Concurrent):同时发生,但是不一定同时做。打个比方,开始吃饭的时候突然来了电话,吃饭和电话同时发生,我吃一口饭说一句话,吃饭和说话不同时进行但是好像在同时进行。

1.8.3 Parallel Scavenge收集器

与ParNew几乎一样,但是注重的是不同方面。

是JDK1.8的默认收集器。

  • Parallel Scavenge 收集器关注点是==吞吐量(高效率的利用 CPU)==
  • CMS 等垃圾收集器的关注点更多的是用户线程的==停顿时间(提高用户体验)==

所谓吞吐量就是 CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值:$ CPU吞吐量 = {运行用户代码时间 \over 总消耗时间} $

ParallelScavege

  • 新生代:复制算法
  • 老年代:标记-整理算法

Parallel Scavenge 收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解,手工优化存在困难的时候,使用 Parallel Scavenge 收集器配合自适应调节策略,把内存管理优化交给虚拟机去完成也是一个不错的选择。

1.8.4 Serial Old收集器

单线程Serial的老年代版本。

标记-整理算法。

 和Serial 收集器相似

  • JDK1.5以前版本,Serial Old + Parallel
  • CMS的后备方案

1.8.5 Parallel Old 收集器

Parallel Scavenge的老年代版本。

多线程,标记-整理算法。

和ParallelScavege相似

注重吞吐量和CPU资源的场景可以使用Parallel Scavenge 和 Parallel Old

1.8.6 CMS收集器

针对老年代的收集器,目的是尽量缩短停顿时间。

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用。

CMS(Concurrent Mark Sweep)收集器是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。

CMS:Concurrent Mark Sweep,并发-标记-清除,所以说是标记-清除算法。

其稍微复杂些,分为4个步骤

CMS收集器

  • 初始标记: 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快 ;
  • 并发标记: 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方
  • 重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
  • 并发清除: 开启用户线程,同时 GC 线程开始对GC Roots不可达对象做清扫。

主要优点:并发收集、低停顿

但是它有下面三个明显的缺点:

  • 对 CPU 资源敏感;
  • 无法处理浮动垃圾;
  • 它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生。

1.8.7 G1垃圾收集器

G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征.

首先将堆内存划分为几个独立区域,然后q后台维护一个优先级列表,首先回收优先级高的,垃圾最多的内存区域。

对CMS的主要改进:

  • 基于标记-整理算法,不会产生内存碎片
  • 可以预测的停顿,精确控制停顿时间,不牺牲吞吐量的前提下实现短停顿。

文章作者: SongX64
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SongX64 !
  目录