垃圾回收器是JVM中最重要的组件之一,几乎每一个JDK的大版本都对垃圾回收进行重大的更新。另外,由于JDK发布策略的改变,在最近3年的版本发布中,每一个大版本都至少合入一个(甚至数个)关于垃圾回收的JEP。垃圾回收的快速发展主要受两个方面的影响:一方面是现代计算机的配置越来越好,应用实际可使用的内存也越来越多(虽然微服务架构改变了这一现象,但是微服务拆分过多,将导致公共资源消耗过多,这是JDK的另外一个发展方向);另一方面是应用性能要求也越来越高,期望垃圾回收尽可能少的暂停。这些诉求要求不断优化垃圾回收,甚至出现新的垃圾回收实现。
根据JDK版本支持的策略,JDK 8、JDK 11和JDK 17是目前长期支持的版本。目前这3个版本共支持7个垃圾回收器,分别是串行回收(简称Serial GC)、并行回收(Parallel Scavenge,简称Parallel GC)、并发标记清除(Concurrent Mark Sweep,简称CMS)、垃圾优先(Garbage First,简称G1)、Shenandoah GC、ZGC、Epsilon(实验特性,仅支持分配不回收,实际场景中不会采用)。由于垃圾回收技术发展很快,所以这3个版本中JDK支持的垃圾回收器并不完全相同,其中CMS仅在JDK 8和JDK 11中支持,ZGC在JDK 11中为实验特性,在JDK 17中为正式产品,Shenandoah在JDK 17中为正式产品,Epsilon在JDK 11和JDK 17中为实验特性。
JVM实现的垃圾回收算法从不同的角度可以归属到不同的类别。通常会从执行角度和内存管理角度进行划分。
从执行角度可以分为以下3种:
从内存管理角度可以分为以下两种:
按照执行和内存管理的角度,JVM支持的垃圾回收可以归纳如下:
在垃圾回收的实现中,可能会根据对象的生命周期管理实现分代,不同生命周期的对象放入不同的内存区域,不同的内存区域通常采用不同的回收算法。按照分代可以将垃圾回收器划分为单代内存回收器和两代内存回收器。单代内存回收器采用一种回收算法,两代内存回收器通常采用两种算法或者采用同一种算法但不同的回收策略。按照分代的划分,JVM支持的垃圾回收可以归纳如下:
ZGC和Shenandoah目前都有分代实现的JEP提案。
第二部分会详细介绍JVM支持的垃圾回收器,分为6章:
第3章介绍串行回收。串行回收采用分代实现,其中新生代采用变异Cheney复制算法,不使用额外的数据结构完成内存空间活跃对象的复制;采用标记压缩算法处理整个内存空间内存不足的场景。除了介绍算法的实现外,本章还会介绍分代的原理、代际引用关系管理等细节。
第4章介绍并发标记清除(简称CMS)。CMS是一个组合算法,也是采用分代实现,其中新生代采用并行复制回收算法(称为ParNew),老生代采用CMS算法,整个内存空间不足时采用标记压缩算法。本章着重介绍并发标记算法。
第5章介绍并行回收。并行回收也采用分代实现,新生代采用并行复制算法(简称Parallel GC),整个内存不足时采用并行的标记压缩算法。本章着重介绍并行标记压缩算法。
第6章介绍垃圾优先回收(简称G1)。G1也是采用分代实现,但是内存管理采用了分区的方式,另外,G1的回收是以停顿时间为目标,它是一款停顿时间基本可控的垃圾回收。本章主要介绍G1如何实现停顿时间可控,以及G1算法详情。
第7章介绍Shenandoah。Shenandoah是一款并发垃圾回收器,可以简单地认为它在G1的基础上将并行回收增强为并发回收。本章详细介绍并发回收算法、Shenandoah实现的原理和演化。
第8章介绍ZGC。ZGC也是一款并发垃圾回收器,它采用了另外一种实现方式来实现并发。本章详细介绍ZGC使用到的一些技术,如Color Pointer、读屏障等。