Hotspot早期的垃圾收集器简介

Posted by Night Field's Blog on November 3, 2020

前言

很多人的博文里面会提到JVM三种垃圾收集器:串行,并行和并发。这么分类也不能说错,但事实上也没有这么简单。本文简要介绍Hotspot早期的垃圾收集器(Garbage Collector)。

名词解释

  • 年轻代和老年代:JVM中不同的对象,生命周期是不同的。比如线程中的临时变量,在方法结束之后便会被销毁;而静态变量,则会一直存在直到其所对应的类被销毁为止。基于这样的事实,才有了分代收集的概念:将JVM堆分为年轻代老年代年轻代存放刚被创建的对象,老年代存放经过多次GC之后依然存活的对象。一般年轻代空间比较小,垃圾收集速度快,触发次数频繁,Minor GC就发生在年轻代老年代空间比较大,垃圾收集速度慢,触发频率低,Full GC会包含老年代的回收。
  • Stop-The-World(STW):垃圾收集器工作的时候,为了防止与应用程序线程相互干扰,会暂停应用线程。所以对于程序来说,垃圾收集时就像时间被停止了一般。
  • 标记-复制算法(copying):垃圾收集器的收集策略,将存活的对象标记出来,统一复制到一块连续的内存之中。这种算法要求有一块足够大的空间可以放下所有存活的对象。
  • 标记-清除算法(mark-sweep):垃圾收集器的收集策略,将存活的对象标记出来,然后清除掉死亡的对象。在连续的内存中清除掉一部分死亡对象之后,会导致内存碎片的产生。
  • 标记-清除-压缩算法(mark-sweep-compact):垃圾收集器的收集策略,在标记-清除算法之外,将存活的对象进行压缩,可以想象成将对象往内存的一边移动以防止内存碎片。

各收集器简介

Our Collectors

上面这张图参考自Oracle官博,每个小方框代表了一种收集器,可以看到,早期的收集器有六种,三个在年轻代,三个在老年代。收集器之间的连线表示了,它们之间是否可以一起工作。

  • 老年代串行(Serial Old):单线程的收集器,采用标记-清除-压缩算法,会STW
  • 老年代并发(CMS):从名字Concurrent Mark Sweep看出,它采用标记-清除算法,大部分时间和应用程序线程并发,极短的时间会STW
  • 老年代并行(Parallel Old):多线程的收集器,采用标记-压缩算法,会STW
  • 年轻代串行(Serial):单线程的收集器,采用标记-复制算法,会STW
  • 年轻代并行(Parallel Scavenge):多线程的收集器,采用标记-复制算法,会STW
  • 年轻代并行(ParNew):多线程的收集器,采用标记-复制算法,会STW。它与Parallel Scavenge的区别是,对CMS收集器做了兼容,如在适当的地方加了线程间的同步处理。

收集器与JVM参数

可以用JVM启动参数来显示指定选择何种收集器。

  • -XX:+UseSerialGC:年轻代是串行(Serial),老年代是串行(Serial Old)。
  • -XX:+UseParNewGC:年轻代是并行(ParNew),老年代是串行(Serial Old)。
  • -XX:+UseConcMarkSweepGC:年轻代是并行(ParNew),老年代是并发(CMS)和串行(Serial Old)。
  • -XX:+UseParallelGC:年轻代是并行(Parallel Scavenge),老年代是串行(Serial Old)。
  • -XX:+UseParallelOldGC:年轻代是并行(Parallel Scavenge),老年代是并行(Parallel Old)。

注意:

  1. 老年代的串行收集器(Serial Old)可以和任意一个年轻代的收集器一起工作。UseSerialGCUseParNewGCUseParallelGC都只指定了年轻代的收集器,老年代默认还是用的串行收集器(Serial Old)。
  2. 为什么打开-XX:+UseConcMarkSweepGC之后,老年代会有两种收集器?前面有说到,CMS采用的标记-清除算法会产生内存碎片,所以当内存碎片化到一定程度之后可能导致无法继续分配新的对象(从年轻代promote上来的对象),此时会触发一次串行的Full GC(带压缩),通常会导致应用程序长时间的停顿。至于为什么不退化成并行收集器(Parallel Old),只能说开发者偷懒了…
  3. -XX:+UseConcMarkSweepGC-XX:+UseSerialGC不能一起使用,否则会报收集器冲突的错。

总结

本文简要介绍了所谓的串行(Serial),并行(Parallel)和并发(CMS)收集器,以及相应的启用参数。因为目前还有很多公司还在用JAVA8甚至之前的版本,所以了解它们还是很有必要的。

参考

Our Collectors