GC-引用计数法

给每个block引入‘计数器’,表示对象的引用次数
这里写图片描述


计数器的增减

  • 在申请内存时会修改计数器:
new_obj(size){
    obj = pickup_chunk(size, $free_list)
    //引用计数法中所有空闲对象都在free_list中
    if(obj == NULL)
        allocation_fail()
    else
        //申请内存成功会更新为1
        obj.ref_cnt = 1
        return obj
}
  • update_ptr()用于更新指针ptr,使其指向对象obj,同时进行计数的增减
update_ptr(ptr, obj){
    //对指针 ptr 新引用的对象(obj)的计数器进行增量操作
    inc_ref_cnt(obj)
    //对指针 ptr 之前引用的对象(*ptr)的计数器进行减量操作
    dec_ref_cnt(*ptr)
    // 指针ptr指向新的obj
    *ptr = obj
}

inc_ref_cnt(obj){
    obj.ref_cnt++
}

dec_ref_cnt(obj){
    obj.ref_cnt--
    if(obj.ref_cnt == 0)
        for(child : children(obj))
            dec_ref_cnt(*child)
        //将obj连接到free_list
        reclaim(obj)
}

优点

  • 可即刻回收垃圾:当计数值为0时,会马上回收对象到free_list,提高内存使用效率
  • 最大暂停时间短:此方法只有当mutator更新指针时才会执行垃圾回收,有效减少暂停时间
  • 没必要从根指针开始查找,减少查询时间。比如在分布式系统中会再节点内用标记-清除算法,节点间的引用时则用引用计数法。

缺点

  • 计数器的增减操作频繁
  • 计数器需要占用一定的内存
  • 实现繁琐,*ptr=obj的地方要重写成update_ptr()
  • 循环引用无法回收

延迟引用计数法

目的是改善计数器值的增减处理繁重的问题。
使用一个ZCT(Zero Count Table)来记录计数器值在dec_ref_cnt()函数作用下变为0的对象
这里写图片描述
对应的dec_ref_cnt(),new_obj()方法:

dec_ref_cnt(obj){
    obj.ref_cnt--
    if(obj.ref_cnt == 0)
        if(is_full($zct) == TRUE)
            //zct满了,扫描去除空闲的block
            scan_zct()
        //将当前的对象写入ZCT
        push($zct, obj)
}

new_obj(size){
    obj = pickup_chunk(size, $free_list)
    if(obj == NULL)
        scan_zct()
        obj = pickup_chunk(size, $free_list)
        if(obj == NULL)
            allocation_fail()
    obj.ref_cnt = 1
    return obj
}

对应的scan_zct()函数,找到当前空闲的block,清除并放到free_list 中

scan_zct(){
    for(r : $roots)
        (*r).ref_cnt++

    for(obj : $zct)
        if(obj.ref_cnt == 0)
            remove($zct, obj)
            delete(obj)

    for(r : $roots)
        (*r).ref_cnt--
}

//先递归减少子对象的计数,如果为0则继续释放,重新挂载到free_list上
delete(obj){
    for(child : children(obj)
        (*child).ref_cnt--
        if((*child).ref_cnt == 0)
            delete(*child)

    reclaim(obj)
}

优点

  • 减少计数器增减的频繁调用

缺点

  • 垃圾不能马上被回收,失去可即刻回收垃圾的优点
  • scan_zct()会加大最大暂停时间,时间长度和ZCT的长度成正比

Sticky引用计数法

使用引用计数法时要考虑的一个问题就是计数器的位宽多大合适,大了比较消耗空间,小了又可能溢出。
解决方法:

什么也不做

这样是有溢出的风险,可能会内存泄漏,但是一般计数器都在0-1变化,溢出的场景很少

用标记-清除算法来管理

不仅可以解决溢出的问题,还能解决循环引用的问题。缺点就是标记-引用算法的缺点【】

1位引用计数法

not write

部分标记-清除算法

not write

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值