JVM 常见的垃圾回收算法
1. 前言
本节主要讲解垃圾回收算法,并对每一种算法进行讲解。垃圾回收算法在垃圾回收器中占据着十分重要的地位,对本节内容一定要格外重视。本节主要内容如下:
- 标记-清除(Mark-Sweep)算法的原理及缺陷,为本节重点内容之一;
- 复制(coping)算法的原理及缺陷,为本节重点内容之一;
- 标记-整理(Mark-Compact)算法的原理及缺陷,为本节重点内容之一;
- 分代收集理论的原理及思想,为本节重点内容之一;
通篇皆为重点内容,务必要用心学习。
2. 垃圾回收算法种类
我们先来讨论一个问题,垃圾回收算法有几种?
如果单纯从一些博客或者论坛上的内容来说,部分作者会将垃圾回收分为如下 4 种算法:
- 标记-清除(Mark-Sweep)算法;
- 复制(coping)算法;
- 标记-整理(Mark-Compact)算法;
- 分代收集算法。
但是这种分类是不准确的,准确来说,垃圾回收只有 3 种算法:
- 标记-清除(Mark-Sweep)算法;
- 复制(coping)算法;
- 标记-整理(Mark-Compact)算法。
为什么会有所谓的“分代收集算法”呢? 此处我们埋下一个伏笔,后文中我会在适当的地方给予解释。
3. 标记-清除(Mark-Sweep)算法
标记 - 清除(Mark-Sweep)算法是最基本的算法。
基本概念:标记-清除算法就如同它的名字一样,分为“标记”和“清除”两个阶段:
- 首先标记出所有需要回收的对象,这就是标记阶段;
- 标记完成后统一回收所有被标记的对象,这就是所谓的清除阶段。
缺点:这种算法的不足主要体现在效率和空间。
- 从效率的角度讲:标记和清除两个过程的的效率都不高;
- 从空间的角度讲:标记清楚后会产生大量不连续的内存碎片,内存碎片太多可能会导致以后程序运行过程中在需要分配较大对象时,无法找到足够的连续内存而不得不提前触发一次垃圾回收动作。
为了更加透彻的理解标记-清除(Mark-Sweep)算法,我们来看下如下示意图,通过直观的图形展示,彻底搞懂标记-清除(Mark-Sweep)算法。
4. 复制(coping)算法
Tips:前文提到过,标记-清除(Mark-Sweep)算法从效率的角度讲,"标记"和"清除"两个过程的的效率都不高,为了提升效率,我们引出了复制(coping)算法。
基本概念:复制算法是为了解决效率问题而出现的,它将可用的内存分为两块,每次只用其中的一块,当这一块内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已经使用过的内存一次性清理掉。这样每次只需要对整个半区进行内存回收,内存分配的执行过程如下图所示:
缺点:不过这种算法有个缺点,内存缩小为原来的一半,这样代价太高了。
现在的商用模拟机都采用这种算法来回收新生代,不过研究表明1:1的比例非常不科学,因此新生代的内存被划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。
每次回收时,将Eden和Survivor中还存活着的对象一次性复制到另外一块Survivor空间上,最后清理掉Eden和刚才使用过的Survivor空间。
HotSpot虚拟机默认Eden区和Survivor区的比例为8:1,意思是每次新生代中可用内存空间为整个新生代容量的90%。当然,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖老年代进行分配担保(Handle Promotion)。
5. 标记-整理(Mark-Compact)算法
Tips:复制算法在对象存活率较高的场景下要进行大量的复制操作,效率还是很低。并且每次只使用一半的内存空间,资源浪费严重。标记-整理(Mark-Compact)算法解决了内存利用率的问题,并且减少了大量复制的问题。
根据老年代的特点,有人提出了另外标记-整理(Mark-Compact)算法,标记过程与标记-整理(Mark-Compact)算法一样,不过不是直接对可回收对象进行整理,而是让所有存活对象都向一端移动,然后清理掉边界以外的内存。标记-整理算法的工作过程如图:
6. 分代清理
问题:我们上文埋下了伏笔,分代清理到底是不是第四种算法呢?
解答:不是,我们通常称之为分代收集理论,或称之为分代收集思想。目前虚拟机基本都采用分代收集理论来进行垃圾回收。
分代收集理论结合了以上的 3 种算法,根据对象的生命周期的不同将内存划分为几块,然后根据各块的特点采用最适当的收集算法。准确的说,分代收集理论就是在不同的内存区域使用不同的算法,它是 以上 3 种算法的使用者。
因此说,分代清理并非是一种单独的算法,而是一种收集理论。
7. 小结
本节内容主要讲解了垃圾回收的 3 种算法和分代收集理论。通篇皆为重点掌握内容,是垃圾回收的核心知识点。学习者可以结合给出的示意图进行理解,这样能够更好地掌握本节所讲的内容。