3.5 经典垃圾收集器

如果说收集算法是内存回收的方法论,那垃圾收集器就是内存回收的实践者。《Java虚拟机规范》中对垃圾收集器应该如何实现并没有做出任何规定,因此不同的厂商、不同版本的虚拟机所包含的垃圾收集器都可能会有很大差别,不同的虚拟机一般也都会提供各种参数供用户根据自己的应用特点和要求组合出各个内存分代所使用的收集器。

本节标题中“经典”二字并非情怀,它其实是讨论范围的限定语,这里讨论的是在JDK 7 Update 4 之后(在这个版本中正式提供了商用的G1收集器,此前G1仍处于实验状态)、JDK 11正式发布之前,OracleJDK中的HotSpot虚拟机[^1]所包含的全部可用的垃圾收集器。使用“经典”二字是为了与几款目前仍处于实验状态,但执行效果上有革命性改进的高性能低延迟收集器区分开来,这些经典的收集器尽管已经算不上是最先进的技术,但它们曾在实践中千锤百炼,足够成熟,基本上可认为是现在到未来两、三年内,能够在商用生产环境上放心使用的全部垃圾收集器了。各款经典收集器之间的关系如图3-6所示。

image-20210916172926747

图3-6 HotSpot虚拟机的垃圾收集器[^2]

图3-6展示了七种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用[^3],图中收集器所处的区域,则表示它是属于新生代收集器抑或是老年代收集器。接下来笔者将逐一介绍这些收集器的目标、特性、原理和使用场景,并重点分析CMS和G1这两款相对复杂而又广泛使用的收集器,深入了解它们的部分运作细节。

在介绍这些收集器各自的特性之前,让我们先来明确一个观点:虽然我们会对各个收集器进行比较,但并非为了挑选一个最好的收集器出来,虽然垃圾收集器的技术在不断进步,但直到现在还没有最好的收集器出现,更加不存在“万能”的收集器,所以我们选择的只是对具体应用最合适的收集器。这点不需要多加论述就能证明:如果有一种放之四海皆准、任何场景下都适用的完美收集器存在, HotSpot虚拟机完全没必要实现那么多种不同的收集器了。

[^1]: 这里专门强调了OracleJDK是因为要把OpenJDK,尤其是OpenJDK-Shenandoah-JDK8这种Backports 项目排除在外,在本书故事的时间线里,Shenandoah要到OpenJDK 12才会登场,请读者耐心等待。
[^2]: 图片来源:https://blogs.oracle.com/jonthecollector/our_collectors。
[^3]: 这个关系不是一成不变的,由于维护和兼容性测试的成本,在JDK 8时将Serial+CMS、 ParNew+Serial Old这两个组合声明为废弃(JEP 173),并在JDK 9中完全取消了这些组合的支持(JEP 214)。