简述 垃圾回收算法(上)

7 篇文章 0 订阅

前情提要,我们知道内存空间是有限的,对象存放在内存中,随着对象不断的增加,内存空间总会有占满的一天。这时候,就需要对内存空间进行管理,将已经没用的对象进行回收,清理出足够的空间存放新的对象。

那么,JVM 对于垃圾对象是怎么回收呢?本文将简述几种垃圾回收算法,废话少说,开始发车!


标记-清除算法

这是最基础的,也是最容易实现垃圾回收算法,它分为两个步骤:

标记 和 清除

  • 标记:标记出需要被回收的对象

  • 清除:将被标记的对象进行回收。

下面用一张图演示整个垃圾回收过程:

图1

那么,标记-清除算法有什么优缺点呢?

优点:简单!

缺点

  • 标记和清除需要经历了两轮遍历,效率比较低。

  • 清除垃圾之后,将会产生大量的 不连续 的碎片空间。

这里有一个疑问,大量的不连续的碎片空间有什么坏处呢?

以图1 清除后 的内存空间为例,分以下几种情况分析:

(1)需要分配3格的空间

首先,我们要知道,这种算法模式下,JVM 会维护一个空闲列表,记录空闲空间的位置,分配空间的时候依据这个列表来查找空闲空间。

当需要分配3格空间的时候,从头遍历空闲列表,只有当遍历到最后,才能找到足够的空间。

像这种需要遍历到最后才能找到合适空间的情况,这也是一种开销。

(2)需要分配5格空间

需要分配5格空间时,从头到尾遍历空闲列表,并没有找到足够的空间。

图1所示,清除后的空闲空间的总量超过5格,然而不存在一段连续的5格空间,因为遍历后找不到足够的空间存放。

那么,这时候不得不触发一次垃圾回收,以获取足够的空间。

这种情况就像房间不进行整理,东西随处乱放,即使剩余很多实际空间,当需要放进大物件的时候,找不到一块合适的地方放置,只能对房间进行清理或整理,腾出足够的空间。


标记-压缩算法

标记-清除算法 最明显的一个缺点就是产生大量的 不连续 的碎片空间,针对这个缺点进行优化改进,在标记-清除的中间,添加 压缩 操作,对存活对象进行 整理,目的是为了将空间空间进行整合,这就是标记-压缩算法。

下面还是用一张图演示整个垃圾回收过程:

图2

压缩 主要是将所有存活的对象都移动到一端,然而,对象之间基本上存在引用,例如 4 引用了 8,这意味着 4 需要存储 8 的地址,每次 8 进行移动,4 都需要重新存储 8 的地址。

因此,压缩并非简单的往前移动,压缩之前,需要先计算每个存活对象的新地址,这就需要多次遍历存活对象,避免出现压缩过程中出现覆盖存活对象的情况。

例如,上图整理后的结果,其实中间省略了复杂的计算,并非 148 按顺序简单的往前移动。

那么,标记-压缩算法有什么优缺点呢?

优点

  • 解决了 标记-清除算法 会产生碎片空间的问题。

缺点

  • 压缩 需要移动存活对象到一端,而且保证移动的位置不会覆盖存活对象,就必须通过计算找到合适的位置,这就产生了额外的开销。

标记-复制算法

同样是针对 标记-清除算法 产生大量的 不连续 的碎片空间的缺点,不同于 标记-压缩算法,标记-复制算法 将内存空间任性的分为两块区域,两块区域交替使用。因此,实际投入使用的只有其中一块区域,即总空间的一半。

下面还是用一张图演示整个垃圾回收过程:

图3

如图3所示,内存空间被分为 A区 和 B区 两块区域,每次只使用其中一块区域(例如A区),当空间不足需要垃圾回收时,将 A区 的存活对象复制到 B区 的一端后,直接清空 A区 的空间。

当空间再次不足的时候,重复以上的操作,两个区域替换使用。

那么,标记-复制算法有什么优缺点呢?

优点

  • 相对标记-压缩算法,不需要对存活对象进行多次遍历,计算新地址,直接复制到另一个区域就可以了。

缺点

  • 只能使用一半的内存空间,空间利用率低。

  • 当存活对象较多的时候,需要进行大量的复制操作,效率下降。

标记-压缩 和 标记-复制 之间的区别,可以想象成房间需要添置新的家具,可是没有一块完整的空间来放置,需要我们对房间的布局进行整理。

标记-压缩:就是我只有一间房,整个房间进行重新布局,首先做好详细的规划,目标是把所有家具都放得更加紧凑,尽量将腾出的空间集中在一块,然后把新家具放置进去。

标记-复制:就是我有两间房,我不想动脑做计划,每次就直接将东西搬到另一间房,所有家具按顺序排放,剩下的空间就可以放置新家具。


再说一句

标记-清除 作为最简单的垃圾回收算法,最致命的缺点就是产生大量的碎片空间,针对这个缺点的优化,演变出 标记-压缩 和 标记-复制 这两种算法。

然而,标记-压缩 和 标记-复制 各自的优缺点都相对比较极端,从时间和空间的角度,标记-压缩牺牲了时间,标记-复制牺牲了空间。

那么,是否有一种算法能够平衡这两者的优缺点,达到更高的效率呢?没错,就是分代算法。它根据对象生命周期的特征,将内存空间合理的划分出不同的区域,建立相关的规则,更加高效的管理内存空间。

下一篇文章,将会带各位了解 分代算法 的奥妙之处,敬请期待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值