垃圾回收的算法与实现(一)三类基本算法

GC 要做两件事

1. 找到内存空间里的垃圾

2. 回收垃圾,让程序员能再次利用这部分空间

主要有三大类算法其他都是扩展

  • GC 标记- 清除算法
  • 引用计数法
  • GC 复制算法

GC 标记- 清除算法

简单描述:分为标记阶段和清楚阶段。标记阶段遍历堆(根的直接引用 然后递归)为所有的活动对象打上标记。清除阶段(从堆的开始到结束遍历每一个对象)如果是已经标记的,设置为未标记,未标记的连接到空闲链表(用作以后的分配),如果有连续的分块则合并。

如何分配:遍历空闲链表根据策略选择合适的对象(例如First - fit(遇到大于等于的分块就直接返回)、Best - fit(返回大于等于的最小分块)、Worst - fit(返回最大的分块)

优点:

  • 简单
  • 与保守式GC 算法兼容(也就是不移动对象)

缺点:

  • 碎片化(也就是空闲链表中存在,一堆不连续的小分块,不论采用那种分配策略都无法避免碎片化)
  • 分配速度慢(每次分配都需要遍历空闲链表,举个极端的,每次合适的都是最后一个)
  • 与写时复制技术不兼容(写时复制技术(众多UNIX 操作系统的虚拟存储中用到的高速
    化方法。),复制进程的时候大部分内存不会被复制而是共享,共享内存不能直接重写,想要重写得复制到自己的私有空间,不访问共享内存)

引用计数法

简单描述:每个对象有个计数器,在每次指针更新时,新指向的对象的计数器++,之前指向的对象的计数器--,如果等于0回收,加入空闲链表。

如何分配:遍历空闲链表

优点:

  • 可即可回收垃圾(当计数器为0时直接回收)
  • 最大暂停时间短(每次指针更新时都会回收垃圾)
  • 没有必要沿指针查找(上面的标记清楚算法,需要由根开始查找)

缺点:

  • 计数器值的增减处理繁重
  • 计数器要占用很多位
  • 实现繁琐复杂
  • 循环引用无法回收(比如根引用A ,A和B两个互相引用,当根不引用A的时候 A和B已经是垃圾了,但是互相引用计数器都是1,无法回收)

GC 复制算法

简单描述:把堆平分为From,To两个空间,如果现在活动对象,垃圾是在From空间,从根开始递归(深度遍历),把所有的对象复制到To空间,反之亦然。

如何分配:当前活跃的空间,未分配的部分,按内存顺序分配。

优点:

  • 优秀的吞吐量(能较短时间完成GC,和标记清楚算法比较,标记清楚需要遍历两次,而GC复制遍历一次+复制)
  • 可实现高速分配(直接在未分配的连续空间分配,不需要遍历啥的)
  • 不会发生碎片化(每次执行GC都把活动对象集中在开头,放在堆的一端的行为叫做压缩)
  • 与缓存兼容(深度遍历的复制,有引用关系的对象,在内存中放到了一起)

缺点:

  • 堆使用效率低下(一分为二,只有一半的堆能使用)
  • 不兼容保守式GC 算法
  • 递归调用函数(每次进行复制的时候都要调用函数,递归会消耗栈,所以还可能栈溢出)

补充 :根引用时来自静态变量,cpu寄存器以及局部变量或参数实例的任何引用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值