JVM系列:(十一)GC算法与使用场景

817 阅读3分钟

一 标记-清除算法

该算法的工作过程和其名字一样,分为标记和清除两个阶段;首先标记GC Roots不可达的对象为待回收状态,在标记完成后统一回收所有被标记的对象。

标记-清除算法

1.1 不足之处

  1. 效率不高,标记和清除两个阶段的效率都不高;

  2. 空间零碎,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能导致后面无法分配大对象,然后提前触发垃圾回收动作;

二 复制算法

复制算法是为了解决标记-清楚算法的低效率问题而设计的。它将内存划分为大小相等的两块,每次只使用其中的一块,当这一块用完后,再将还存活的对象复制到另一块上,最后将已使用过的内存空间一次清理掉。

这样每次都是对整个半区进行回收,回收完后也不会出现内存碎片等情况,空白半区只需要按顺序分配内存即可,实现简单,运行高效。

复制算法

2.1 不足之处

  1. 将可用内存缩小为原来的一半,内存过于浪费;

  2. 对象存活率较高时,需要复制的对象较多,效率低;

三 标记-整理算法

针对JVM堆内存中的老龄代对象的存活率高,占用内存大等特点,有人提出了标记-整理算法。该算法类似于标记-清除算法,但后续步骤不是对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

标记-整理算法

3.1 不足之处

  1. 对于前面可回收的对象,需要移动后面还存活对象;

四 分代收集算法

将内存分为两大块,新生代和老龄代,根据对象存活周期各个年代的特点将对象存放在不同块中,针对不同块采用最适当的收集算法进行垃圾回收。

在新生代中,每次垃圾回收时都发现大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集;而老龄代中因为对象存活率高,没有额外空间对它进行分配担保,就必须使用“标记-清除”或者“标记-整理”算法来进行回收;

五 使用场景

我们把上一章说的JVM内存分配的堆内存分配的图拿过来,再结合这章的垃圾收集算法,具体说一下垃圾收集算法在堆内存中的具体使用。

JVM堆内存分配

上图可知,从整体上看。

JVM堆内存 = 新生代 + 老龄代;

新生代 = 伊甸园 + 交换区;

交换区 = from + to;

  1. 新生代+老龄代:分代收集算法;

  2. 老龄代:一般采用“标记-整理”或“标记-清除”算法;

  3. 伊甸园+from或to:复制算法;