终于有一篇能让小白更容易理解GC算法的文章了

本篇文章,在学习JVM的过程中,根据书籍(深入理解Java虚拟机)、网络和个人的一些想法总结而成。

你有我有全都有,风风火火闯九州!

你懂我懂咱都懂,风风火火搞定它!

垃圾收集算法到现在(JDK8)有3种,“标记-清除”算法、“标记-复制”算法、“标记-整理”算法。

发展史以及各个算法诞生时要解决的问题,如下图所示。

GC算法发展史-时间轴图 (1).png

为了更形象的说明这三种算法的区别和含义,举个例子。

割韭菜怎么割比较好,是个技术活:

图片来自百度。

image.png

韭菜地是各种各样的,我们如何才能长的更好?考验技术的时候到了。
image.png

一、算法核心思想介绍

1、标记-清除算法

核心思想:

标记-清除算法就像它的名字一样,算法分为“标记”和“清除”两个阶段,先对可回收的对象进行统一标记,在标记完成后再进行统一的回收调被标记的对象。

也可以反过来,先统一标记存活的对象,然后统一回收未被标记的对象。

标记过程就是对对象进行判定是否可回收,是否属于垃圾的过程。

图片演示:
假如我们有如下内存,我们对其进行使用。
image.png

使用后的结果如下:
image.png

第一步:首先把内存中所有的对象进行检查一遍,是垃圾(可回收)的对象就进行标记。如下图所示,标记成灰色。

image.png

第2步:将标记好的对象,也就是灰色区域的清理掉。

image.png

回收前VS回收后
image.png

可以看到,清理完成后空闲的空间并没有挪动,所以“标记-清理”算法在清理后,整个空间的位置是非常零散的(也就是经常所说的内存碎片,不连续的空间)。

这也就是“标记-清理”算法的不足之处。

如果此时来了一个比较占用大内存的对象,而恰好腾出来的空间装不下来,反而如果把不连续的空间组合到一起就满足了。此时就会抛OOM异常(内存溢出)。

它的主要缺点有两个:

  • 1、执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,此时就会进行大量标记和清除的动作。导致标记

2、标记-复制算法

标记-复制算法常被简称为复制算法。为了解决标记-清除算法面对大量可回收对象时执行效率低的问题。1969年Fenichel提出了一种称为“半区复制”(Semispace Copying)的垃圾收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。如果内存中多数对象都是存活的,这种算法将会产生大量的内存间复制的开销,但对于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存回收,分配内存时也就不用考虑有空间碎片的复杂情况,只要移动堆顶指针,按顺序分配即可。这样实现简单,运行高效,不过其缺陷也显而易见,这种复制回收算法的代价是将可用内存缩小为了原来的一半,空间浪费未免太多了一点。

简单点说:

标记-复制算法,是为了解决标记-清除算法面对大量可回收对象时执行效率低的问题。它将可用内存按容量划分为大小相等的两块区域,每次只使用其中一块。当这一块的内存用完了,就将还活着的对象复制到另外一块上,然后再把已使用过的内存空间清理掉。

垃圾回收前的状态:
image.png

垃圾回收后的状态:

会把另一半中存活的对象,复制到另外一边,然后清除。
如果下次再做垃圾回收的时候,又会复制到另一边,以此类推。

image.png

对比图:
image.png

3、标记-整理算法

标记-复制算法在对象存活率较高时就要进行较多的复制操作,效率将会降低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。

针对老年代对象的存亡特征,1974年Edward Lueders提出了另外一种有针对性的“标记-整理”(Mark-Compact)算法,其中的标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存,“标记-整理”算法的如下图所示。

标记-清除算法与标记-整理算法的本质差异在于前者是一种非移动式的回收算法,而后者是移动式的。

image.png

二、总结

为了更好记住,抛出一个问题,解答一个问题的形式来说明吧。

面试官问:

你了解哪些GC算法,有什么区别,能分别说一下吗?

答:
我们常见的有三个,分别为“标记-清除”算法、“标记-复制”算法、“标记-整理”算法。

其中标记-清除算法是基础,标记-复制算法和标记-整理算法可以说是在标记-清除算法的基础上得以改进不足从而得到的算法。

  • 标记-清除算法就像它的名字一样,分为标记和清除两个阶段。首先对内存中可回收的垃圾对象进行标记,然后统一进行清理。这个标记的过程其实就是判断是否为可回收的垃圾。不足之处就是随着对象的增多,此算法就会消耗很多的时间去完成相应的操作。

  • 标记-复制算法其实就是为了解决标记清除算法效率低的问题。它把内存分为平等的两份空间,每次只使用一份,当触发到垃圾回收时机的时候,会把当前正在使用的这份内存空间中存活的对象,复制到另外一份内存空间,而且是连续的。然后清理刚才复制前的另一空间。不足之处就是如果使用内存达到了50%的情况,就会当作100%的情况,必须借助另外的内存才可以满足,很浪费内存空间。

  • 标记-整理算法是为了解决标记-复制算法内存浪费的问题。标记-整理算法和标记-清理算法差不多,不同之处是,当触发垃圾回收机制的时候,此算法会把存活的对象移动到另一端的内存空间,然后清理掉边界以外的内存空间,而且整理后的内存空间是连续的。

手撕代码八百里 CSDN认证博客专家 Linux 分布式 Java
原名:TrueDei,现:手撕代码八百里

不荒废现在,不畏惧未来!我认为把知识给别人讲会,讲明白,自己才彻底明白。努力把文章写好,写明白每一篇文章,分享给更多人。
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页
实付 49.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值