根可达算法的根_GC垃圾回收算法

GC定义

「GC」是Garbage Collection的缩写,即回收垃圾,那么「垃圾」指的是什么呢?

当然这里指的不是现实世界的垃圾,在程序世界中垃圾定义为

程序不用的内存空间视为垃圾

「GC」需要做的是

❝找到内存里面的垃圾回收垃圾,让内存空间再利用❞

指针

在GC 算法中,指针是不可或缺的。我们用星号(*)访问指针所引用的内存空间。例如:我们把指针「ptr」 指向的对象表示为 *「ptr」

3a1377a234e3d8124b545442f3f430ba.png

对象,头,域

对象和指针

c44fe5e2ee79d739c75db80ae9ef2383.png

对象和指针

mutator

mutator 是Edsger Dijkstra琢磨出来的词,有“改变某物”的意思。说到要改变什么,那就是GC 对象间的引用关系。

mutator 实际进行的操作有以下2 种。

  • 生成对象
  • 更新指针

e583e4b724d47dd1227f27bec4c242bb.png

活动对象与非活动对象

fefc13a314b6cf152e931b731011abe3.png

活动对象与非活动对象

最大暂停时间

因执行「GC」 而暂停执行mutator 的最长时间。如下图,最大暂停时间是A~C 的最大值,也就是B。

32ffe6623445450064e068574771ee4a.png

GC执行图

如上图:假设GC对象的对大小为HEAP_SIZE。在大小为HEAP_SIZE的堆进行内存管理,要花费的时长为(++)。因此,这种情况下GC 的吞吐量为HEAP_SIZE /(A + B + C)。

GC性能评价标准

  • 吞吐量
  • 最大暂停时间(需要缩短最大暂停时间)
  • 堆使用效率(可用的堆越大,GC 运行越快)
  • 访问的局部性

什么是访问的局部性

另一方面,具有「引用关系的对象之间通常很可能存在连续访问」的情况。这在多数程序中都很常见,称为“访问的局部性”。考虑到访问的局部性,把具有引用关系的对象安排在堆中较近的位置,就能提高在缓存中读取到想利用的数据的概率,令mutator高速运行。

垃圾回收算法

GC标记-清除算法

GC 标记- 清除算法由标记阶段和清除阶段构成。标记阶段是把所有活动对象都做上标记的阶段。清除阶段是把那些没有标记的对象,也就是非活动对象回收的阶段。通过这两个阶段,就可以令不能利用的内存空间重新得到利用。

标记阶段

732c9ab108361ae7395fb270652a53bc.png

执行GC前堆的状态

32dbd7283800b02cc63d8a3ef5467919.png

标记阶段结束后堆的状态

搜索对象进行标记是采用的算法:深度优先搜索,,深度优先搜索比广度优先搜索更能压低内存使用量。因此我们在标记阶段经常用到深度优先搜索。

2d3022731e5803d7823d2950afd459bc.png

深度优先搜索

深度优先搜索是纵向搜索,如上图的搜索顺序。

清除阶段

38aa593549ef4a3d74ec51f4dcdacc39.png

清除阶段结束后堆的状态

分配

将回收的垃圾进行再利用,需要分配。在清除阶段,我们把垃圾对象连接到空闲的链表,搜索空闲链表并寻找 大小合适的分块,这项操作就叫作分配。

合并

根据分配策略的不同可能会产生大量的小分块。但如果它们是连续的,我们就能把所有的小分块连在一起形成一个大分块。这种“连接连续分块”的操作就叫作合并(coalescing),合并是在清除阶段进行的。

位图标记

只收集各个对象的标志位并表格化,不跟对象一起管理。在标记的时候,不在对象的头里置位,而是在这个表格中的特定场所置位。像这样集合了用于标记的位的表格称为“位图表格”(bitmap table),利用这个表格进行标记的行为称为“位图标记”。位图表格的实现方法有多种,例如散列表和树形结构和整数型数组等。

22af1c60aad6197b27f54c36e2d8221c.png

位图标记

延迟清除法

清除操作所花费的时间是与堆大小成正比的,如果处理的堆越大,清除算法所花费的时间就越长。

延迟清除法,在标记操作结束后,不一定会进行清除操作,会缩减mutator的暂停时间。

标记清除算法的优缺点

优点:标记清除算法实现简单,与其他的的算法组合也就相对简单;

缺点:标记清楚算法不会移动对象,但容易产生碎片化的空间,造成内存浪费。

如图:

a2e6baaa5eea439b865b44ae90021d11.png

上图的「根」指的是「GC root」,通过「根可达算法」确认是不是垃圾。这里简单介绍下根可达算法的定义:

从GC Root作为起点开始搜索,那么整个连通图中对象都是活的,对于GC Root无法达到的对象便是垃圾对象,随时可被GC回收。

如果我需要3空间的内存,而2空间的内存就存不下。就会被空闲,造成内存浪费。

引用计数法

引用计数法中引入了一个计数器。计数器表示的是对象的引用次数。如果对象引用次数为0,那么这个对象可以被清除。

优缺点

「优点」:可即刻回收垃圾,空间不会被垃圾长久占用。

「缺点」:计数器值的增减处理繁重,计数器也需要占用内存。无法回收循环引用。

GC复制算法

简单来说,GC复制算法就是把空间里的活动对象复制到其他空间。把原空间里的所有对象都回收掉。如图所示:

4e68ed706b8d0fea916dc9b4203929a7.png

当From空间被占满时,GC将活动的对象全部复制到To空间。当复制完成后,该算法会将From空间和To空间互换,GC结束。。From 空间和To 空间大小必须一致。这是为了保证能把From 空间中的所有活动对象都收纳到To 空间里。

优缺点

优秀的吞吐量,可实现高速分配,不会发生碎片化。

但是复制算法需要把堆进行二等分,只有一半的堆能被使用。造成堆的浪费。还有复制算法在复制某个对象时要递归复制它的对象,这里会带来额外的负担,有栈溢出的可能。

GC标记压缩算法

此算法分为标记阶段和压缩阶段,标记阶段同上面几种算法的标记功能一样,我们来说说压缩阶段,分为3步骤:

❝设定forwarding 指针更新指针移动对象❞

标记压缩实际上就是将活动的对象xi整理到一边,尽量的减少碎片化,来看看实际的效果:

8c7565b84dd2e8560d19ea391e3b402a.png

image-20200730141439426

优缺点

可有效利用堆,但是压缩会有计算成本。

GC主要的回收算法就介绍这么多了,其实际的算法很复杂。有兴趣的可以自行研究。

「参考:」

《垃圾回收的算法与实现》 作者: 中村成洋 / 相川光

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值