JVM 垃圾回收器

君子以自强不息。

简介

基于分代管理和回收算法,结合回收的时机,JVM 实现垃圾回收器了:串行回收、并行回收、并发标记回收(CMS)和垃圾优先回收。

串行回收

串行回收使用单线程进行垃圾回收,在回收的时候 Mutator 需要 STW(Stop-the-world,指停止一切 Java 应用线程)。新生代通常采用复制算法,老生代通常采用标记压缩算法。

并行回收

并行回收使用多线程进行垃圾回收,在回收的时候 Mutator 需要暂停,新生代通常采用复制算法,老生代通常采用标记压缩算法。

并发标记回收

并发标记回收(CMS)的整个回收期间划分成多个阶段:初始标记、并发标记、重新标记、并发清除等。在初始标记和重新标记阶段需要暂停 Mutator,在并发标记和并发清除期间可以和 Mutator 并发运行。这个算法通常适用于老生代,新生代可以采用并行回收。

垃圾优先回收

垃圾优先回收器(Garbage-First,也称为 G1)从 JDK7 Update 4开始正式提供。G1 垃圾回收器的设计和前面提到的3种回收器都不一样,它在并行、串行以及 CMSGC 针对堆空间的管理方式上都是连续的。

连续的内存将导致垃圾回收时收集时间过长,停顿时间不可控。因此 G1 将堆拆成一系列的分区(Heap Region),这样在一个时间段内,大部分的垃圾收集操作只针对一部分分区,而不是整个堆或整个(老生)代。

在 G1 里,新生代、老生代就是一系列的内存分区,意味着不用再要求新生代、老生代是一个连续的内存块。这样也就不需要在 JVM 运行时考虑哪些分区是老生代,哪些是新生代。事实上,G1 通常的运行状态是:映射 G1 分区的虚拟内存随着时间的推移在不同的代之间切换。例如一个 G1 分区最初被指定为新生代,经过一次新生代的回收之后,会将整个新生代分区都划入未使用的分区中,那它可以作为新生代分区使用,也可以作为老生代分区使用。同样,在一个老生代分区完成收集之后,它就成为了可用分区,在未来某个时候可作为一个新生代分区来使用。

G1 新生代的收集方式是并行收集,采用复制算法。与其他 JVM 垃圾回收器一样,一旦发生一次新生代回收,整个新生代都会被回收,这也就是我们常说的新生代回收(Young GC)。

G1 和其他垃圾回收器的区别

  • G1 会根据预测时间动态改变新生代的大小:

  • G1 老生代的收集在任意时刻只有一部分老生代分区会被回收,并且,这部分老生代分区将在下一次增量回收时与所有的新生代分区一起被收集。也就是混合回收(Mixed GC)。在选择老生代分区的时候,优先考虑垃圾多的分区,这也正是垃圾优先这个名字的由来。