终于有一篇能让小白更容易理解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%的情况,必须借助另外的内存才可以满足,很浪费内存空间。
  • 标记-整理算法是为了解决标记-复制算法内存浪费的问题。标记-整理算法和标记-清理算法差不多,不同之处是,当触发垃圾回收机制的时候,此算法会把存活的对象移动到另一端的内存空间,然后清理掉边界以外的内存空间,而且整理后的内存空间是连续的。
目录
相关文章
|
7月前
|
安全 算法 Java
HotSpot中GC算法的实现
HotSpot中GC算法的实现
40 0
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
75 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
2月前
|
算法 Java
JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
本文详细介绍了JVM中的GC算法,包括年轻代的复制算法和老年代的标记-整理算法。复制算法适用于年轻代,因其高效且能避免内存碎片;标记-整理算法则用于老年代,虽然效率较低,但能有效解决内存碎片问题。文章还解释了这两种算法的具体过程及其优缺点,并简要提及了其他GC算法。
 JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
|
2月前
|
缓存 算法 Java
GC垃圾收集算法
这篇文章详细讨论了垃圾收集(GC)的几种算法,包括引用计数、可达性分析、标记-清除、标记-复制和标记-整理算法,并介绍了这些算法的优缺点和适用场景。
31 0
GC垃圾收集算法
|
5月前
|
存储 监控 算法
(六)JVM成神路之GC基础篇:对象存活判定算法、GC算法、STW、GC种类详解
经过前面五个章节的分析后,对于JVM的大部分子系统都已阐述完毕,在本文中则开始对JVM的GC子系统进行全面阐述,GC机制也是JVM的重中之重,调优、监控、面试都逃不开的JVM话题。
161 8
|
4月前
|
算法 Java 应用服务中间件
探索JVM垃圾回收算法:选择适合你应用的最佳GC策略
探索JVM垃圾回收算法:选择适合你应用的最佳GC策略
|
5月前
|
算法 搜索推荐
推荐系统,推荐算法01,是首页频道推荐,一个是文章相似结果推荐,用户物品画像构建就是用户喜欢看什么样的文章,打标签,文章画像就是有那些重要的词,用权重和向量表示,推荐架构和业务流
推荐系统,推荐算法01,是首页频道推荐,一个是文章相似结果推荐,用户物品画像构建就是用户喜欢看什么样的文章,打标签,文章画像就是有那些重要的词,用权重和向量表示,推荐架构和业务流
|
6月前
|
人工智能 算法 BI
一篇文章讲明白KMP算法(俗称看毛片算法)
一篇文章讲明白KMP算法(俗称看毛片算法)
61 0
|
6月前
|
算法 Java 云计算
JVM垃圾回收的历史演进:从GC算法到垃圾回收器选择
JVM垃圾回收的历史演进:从GC算法到垃圾回收器选择
|
6月前
|
算法 JavaScript 安全
一篇文章讲明白JavaScript_提交表单和MD5算法密码加密
一篇文章讲明白JavaScript_提交表单和MD5算法密码加密
60 0