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

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

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

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

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

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

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

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

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

图片来自百度。

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

一、算法核心思想介绍

1、标记-清除算法

核心思想:

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

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

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

图片演示:

假如我们有如下内存,我们对其进行使用。

使用后的结果如下:

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

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

回收前VS回收后

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

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

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

它的主要缺点有两个:

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

2、标记-复制算法

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

简单点说:

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

垃圾回收前的状态:

垃圾回收后的状态:

会把另一半中存活的对象,复制到另外一边,然后清除。

如果下次再做垃圾回收的时候,又会复制到另一边,以此类推。

对比图:

3、标记-整理算法

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

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

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

二、总结

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

面试官问:

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

答:

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

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

  • 标记-清除算法就像它的名字一样,分为标记和清除两个阶段。首先对内存中可回收的垃圾对象进行标记,然后统一进行清理。这个标记的过程其实就是判断是否为可回收的垃圾。不足之处就是随着对象的增多,此算法就会消耗很多的时间去完成相应的操作。
  • 标记-复制算法其实就是为了解决标记清除算法效率低的问题。它把内存分为平等的两份空间,每次只使用一份,当触发到垃圾回收时机的时候,会把当前正在使用的这份内存空间中存活的对象,复制到另外一份内存空间,而且是连续的。然后清理刚才复制前的另一空间。不足之处就是如果使用内存达到了50%的情况,就会当作100%的情况,必须借助另外的内存才可以满足,很浪费内存空间。
  • 标记-整理算法是为了解决标记-复制算法内存浪费的问题。标记-整理算法和标记-清理算法差不多,不同之处是,当触发垃圾回收机制的时候,此算法会把存活的对象移动到另一端的内存空间,然后清理掉边界以外的内存空间,而且整理后的内存空间是连续的。
目录
相关文章
|
1月前
|
安全 算法 Java
HotSpot中GC算法的实现
HotSpot中GC算法的实现
16 0
|
4月前
|
算法 Java
JVM GC和常见垃圾回收算法
JVM GC和常见垃圾回收算法
51 0
|
5月前
|
存储 缓存 算法
JVM(四):GC垃圾回收算法
JVM(四):GC垃圾回收算法
|
4月前
|
存储 监控 算法
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
|
3月前
|
算法 安全 Java
「译文」Java 垃圾收集参考手册(三):GC 算法基础篇
「译文」Java 垃圾收集参考手册(三):GC 算法基础篇
|
3月前
|
算法 Java
「译文」Java 垃圾收集参考手册(八):GC 算法总结
「译文」Java 垃圾收集参考手册(八):GC 算法总结
|
4月前
|
存储 算法 Java
JVM GC 算法
对于JVM的垃圾收集(GC),这是一个作为Java开发者必须了解的内容,那么,我们需要去了解哪些内容呢,其实,GC主要是解决下面的三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 回答了这三个问题,也就对于GC算法的原理有了最基本的了解。
|
4月前
|
缓存 算法 JavaScript
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
|
5月前
|
设计模式 缓存 算法
史上最全Java面试题:数据结构+算法+JVM+线程+finalize+GC
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制
|
4天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。