(阅读笔记)垃圾回收的算法与实现 - Reference Counting

本文深入探讨了引用计数法的基础实现及其优缺点,包括计数器操作繁重、占位多、实现复杂和循环引用无法回收等问题。接着介绍了几种改进算法,如延迟引用计数法、Sticky 引用计数法、1 位引用计数法和部分 MarkSweep 算法,分析了它们如何解决原算法的不足。
摘要由CSDN通过智能技术生成


MarkSweep 的逻辑是判断对象是否存在引用,而 引用计数法 则在这个逻辑上更进了一步,引入 计数器的概念来统计对象当前的被引用次数。如果次数为 0 了,那么也就是非活动对象,可以被回收,否则就是活动对象。

基础实现

引用计数法实现的核心是针对计数器本身的增减,并且当减至为 0 的时候,执行回收操作,所以在该算法中并没有如 MarkSweep 中那么明确的 GC 执行开始时间。

代码

计数器修改的时机有两个,分别是对象创建,以及指针更新的时候


// 对象定义
type object struct {
   
	ReferenceCount int
	Filed          interface{
   }
	Next           *object
	Size           int
}

// 新建对象
func NewObject() *object {
   
	return &object{
   
		ReferenceCount: 1,
	}
}

// 指针更新(引用更新)注意增减顺序
func UpdatePointer(ptr **object, o *object) {
   
	increaseObjectRef(o)
	decreaseObjectRef(ptr)
	*ptr = o
}

func increaseObjectRef(o *object) {
   
	o.ReferenceCount++
}

// 减少引用过程伴随对象回收的操作
func decreaseObjectRef(o *object) {
   
	o.ReferenceCount--
	if o.ReferenceCount == 0 {
   
		decreaseObjectRef(o.Next)
		reclaim(o)
	}
}

注意: UpdatePointer 增减计数器的顺序,是先增加被引用对象的计数以后,再减少要变更引用的对象的计数的, 考虑特殊情况,假如两者是相同对象,则会导致出错。因为 decreaseObjectRef 中有对象回收的操作
注意:golang 函数是值传递,所以这里的 UpdatePointer 传参相对原书是有所修改。

优点

  1. 可以立即回收垃圾 (decreaseObjectRef 中实现的)
  2. 最大暂停时间短(可以认为几乎没有,因为该算法的 GC 相关都在对象的操作中完成了)
  3. 没有必要沿指针查找 (没必要由根沿指针查找。当我们想减少沿指 针查找的次数时,它就派上用场了)

缺点

  1. 计数器的操作繁重(尤其是从根出发的引用)
  2. 计数器占位多
  3. 实现繁琐复杂
  4. 循环引用无法回收

下面同样是重点针对缺点做分析

计数器操作繁重

通过代码可以看到,每次指针变化要对应两次计数器的操作,那么当指针变化频繁时,计数器部分的消耗就无法忽视。尤其是从根(调用栈、寄存器)引用的指针变化会非常频繁。

改进措施有

  1. 延迟引用计数法
计数器占位多

这个是存储的问题,严格讲,计数器最大可以到 2 的(机器位数)次方(理论上一个对象可以被引用这么多次数),那么内存浪费就太大了。

改进措施有

  1. Sticky 引用计数法
  2. 1 位引用计数法
实现繁琐复杂

因为那个 UpdatePointer 是要在应用程序内调用的,那么就不能按照语言自身的变更去写 ptr=&obj, 这样是很麻烦的。

循环引用无法回收

假设 A 引用 B 的同时,B 也引用了 A,那么 A 和 B 的引用计数都会是 1,那么在该算法下就无法被回收了

改进措施有

  1. 部分 MarkSweep 算法(4 色算法)

算法改进

  1. 延迟引用计数法 (改善计数繁重)
  2. Sticky 引用计数法(改善计数占位)
  3. 1 位引用计数法(改善计数占位)
  4. 部分 MarkSweep 算法(解决不能回收循环垃圾的问题)

延迟引用计数法

原生算法的计数繁重,尤其是是来自根的引用变化引发的部分,而延迟引用计数法的主要目的就是解决这部分,但是也同时引入了新的计数问题导致与原生算法不能兼容,最后又通过引入新的数据结构 ZCT 以及配套的措施来解决这个问题。所以,该算法可以被分解成两个部分

  1. 根引用变化不使用引用计数法,而是直接修改
  2. 引入的 ZCT ,以及针对 ZCT 部分的逻辑
ZCT

ZCT 就是 zero count table,该表的功能是用来记录下在 decreaseObjectRef (也就是减少引用)时候,计数器变为 0 的对象。当没有空余空间时,则通过扫描 ZCT 判断是否被根引用,如果被引用则跳过,没有引用则进行回收,从而释放空间。

zct 的操作方法有 push

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值