JVM垃圾收集算法简介

387 阅读3分钟

这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

在之前的章节,我们讲了JAVA的内存模型JVM垃圾收集器工作原理,今天我们接着讲JVM的垃圾回收算法。

1. 标记-清除算法

该算法分为标记清除阶段:⾸先标记出所有不需要回收的对象,在标记完成后统⼀回收掉所有没有被标记的对象。它是最基础的收集算法,后续的算法都是对其不⾜进⾏改进得到。这种垃圾收集算法会带来两个明显的问题:

  1. 效率问题:标记和清除的效率都不高,主要是因为内存经过这种算法垃圾收集后变为不规整的内存,标记和清除的效率受到了影响。
  2. 空间问题:因为内存在垃圾收集后会产生大量不连续的内存碎片,导致以后再需要分配较大的对象时找不到连续的内存空间,不得不提前触发另一次垃圾收集。

image.png

2. 复制算法

为了解决效率问题,“复制”收集算法出现了。它可以将内存分为⼤⼩相同的两块,每次使⽤其中的⼀块。当这⼀块的内存使⽤完后,就将还存活的对象复制到另⼀块去,然后再把使⽤的空间⼀次清理掉。这样就使每次的内存回收都是对内存区间的⼀半进⾏回收。

优点:使用这样的方法进行垃圾收集后,内存是规整的,所以不用担心内存碎片等问题,并且因为一次性清理一半的内存,效率很高。

缺点:内存的使用率低,每次只有一半的内存被使用。如果存活大量对象,则需要大量进行复制,消耗系统资源。

image.png

3. 标记-整理算法

根据⽼年代的特点提出的⼀种标记算法,标记过程仍然与“标记-清除”算法⼀样,但后续步骤不是直接对可回收对象回收,⽽是让所有存活的对象向⼀端移动,然后清除掉其余的内存。

优点: 使用这样的方法进行垃圾收集后,内存是规整的,所以不用担心内存碎片等问题。

4. 分代收集算法

当前虚拟机的垃圾收集都采⽤分代收集算法,这种算法根据对象存活周期的不同将内存分为⼏块。⼀般将 java 堆分为新⽣代和⽼年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。

⽐如在新⽣代中,每次收集都会有⼤量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。因此之前讲的内存模型中,2个Survivor区(分别叫from和to)就是使用了这种算法。

而⽼年代的对象存活⼏率是⽐较⾼的,⽽且没有额外的空间对它进⾏分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进⾏垃圾收集。

image.png