GC-引用计数法

引用计数的算法

  • 计数器:对象的被引用数(多少程序引用过这个对象)
  • 计数器值增减
    引用计数法中没有明确启动GC的语句。在mutator的处理过程中通过增减计数器的值来进行内存管理。
    涉及计数器增减的情况 - new_obj()和update_ptr()
  • 创建对象
    引用计数法中,除了free_list中的对象,其余都是活动对象。如果pick_chunk()失败,堆中就没有合适的分块了;如果成功,将该对象计数器置1,说明对象已生成且被引用。
  • 指针更新
    1. reclaim()将obj链接到空闲链表
    2. 先调用inc再调用dec,以处理更新前后指针指向的是同一对象的情况。如果先调用dec,可能导致对象被引用数为0,继续调用inc时所需对象已被回收。
  • 引用计数法特征:mutator和内存管理同时运行。

优点

  • 可即刻回收垃圾
    内存不会被垃圾占用,其他GC算法中直到GC开始执行之前,都有一部分内存被垃圾占用(分块用尽后才会执行GC)。
  • 最大暂停时间短
  • 不必沿指针查找
    相对适用于分布式环境。
    一种做法是各个计算节点内回收垃圾使用GC标记-清除算法,考虑节点间引用关系用引用计数法。

缺点

  • 计数器增减处理繁重
    指针频繁更新导致计数器频繁更新。
  • 计数器占位很多
    用于引用计数的计数器最大必须能数完堆中所有对象的引用数。
  • 实现复杂
  • 循环引用无法回收
    两个或两个以上对象互相循环引用,使计数器都无法清零,即使该对象组都成了垃圾,也无法被程序回收。

延迟引用计数法

  • 是什么
    使从根引用的指针变化不反映在计数器。
    使用ZCT(Zero Count Table),记录调用dec之后计数器值为0的对象(可能是垃圾,也可能不是)。
  • 修改dec函数和内存分配函数
  • scan_zct()
    zct满的时候调用,内存没有合适的分块用于分配时调用。
scan_zct(){
    for (r : $root)
      (*r).ref_cnt++

    for(obj : $zct)
      if (obj.ref_cnt == 0)
        remove($zct, obj) //remove obj from zct 
        delete(obj) //1. 对子对象计数器做--;2. 回收
  
    for (r : $root)
      (*r).ref_cnt--
  • 优点
    减轻指针引用频繁修改导致的计数器增减所带来的负担。
  • 缺点
    不支持立刻回收垃圾
    scan_zct()导致最大暂停时间变长

Sticky引用计数法

1位引用计数法

部分标记-清除算法

你可能感兴趣的:(GC-引用计数法)