内存管理Release和Retain实现原理

引入计数存储在SideTables表中存储结构如图所示。

1.Retain实现原理。

1.1对对象retain之后实现过程。

id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
   assert(!isa.nonpointer);
#endif
   SideTable& table = SideTables()[this];//从SideTables中取出SideTable。
   
   table.lock();
   size_t& refcntStorage = table.refcnts[this];//根据this地址取出refcntStorage
   if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {//如果没有超出引用计数最大值
       refcntStorage += SIDE_TABLE_RC_ONE;//引用计数加4也就是向左移动两位。
   }
   table.unlock();

   return (id)this;
}

复制代码

1.2引用计数值获取。

objc_object::sidetable_retainCount()
{
  SideTable& table = SideTables()[this];

  size_t refcnt_result = 1;
  //对象初始化时默认为1之后每次对对象retain引入计数值加1
  table.lock();
  RefcountMap::iterator it = table.refcnts.find(this);//获取RefcountMap
  if (it != table.refcnts.end()) {//能找到this对象
      // this is valid for SIDE_TABLE_RC_PINNED too
      refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;//
      //it->second是获取到it的value
      //>> SIDE_TABLE_RC_SHIFT上边获取的value向左移动两位获取到引用计数器的值。
      
  }
  table.unlock();
  return refcnt_result;//返回引用计数值
}
复制代码

2.Release实现原理

objc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
#endif
    SideTable& table = SideTables()[this];//获取到SideTable

    bool do_dealloc = false;//是否要被dealloc

    table.lock();//锁住table表
    RefcountMap::iterator it = table.refcnts.find(this);//获取到RefcountMap
    if (it == table.refcnts.end()) {//没有找到this
        do_dealloc = true;
        table.refcnts[this] = SIDE_TABLE_DEALLOCATING;//设置为需要dealloc
    } else if (it->second < SIDE_TABLE_DEALLOCATING) {//没有引用计数值
        // SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
        do_dealloc = true;
        it->second |= SIDE_TABLE_DEALLOCATING;//给it->second赋值
    } else if (! (it->second & SIDE_TABLE_RC_PINNED)) {//引用计数减一
        it->second -= SIDE_TABLE_RC_ONE;
    }
    table.unlock();
    if (do_dealloc  &&  performDealloc) {//对象需要被销毁
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);//发送消息调用dealloc销毁对象。
    }
    return do_dealloc;
}
复制代码

2.1通过this没有找到RefcountMap

如果没找打RefcountMap对象do_dealloc 设置位 true table.refcnts[this] = SIDE_TABLE_DEALLOCATING设置标志位为1为下边清除weak——table——t表中的对象设置为nil做准备。 ##2.2引入计数已经清0

do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;
复制代码

代码和2.1操作相同标志位设置。

2.3引用计数减1。

it->second -= SIDE_TABLE_RC_ONE;
复制代码

2.4根据标志位判断是否需要dealloc。

if (do_dealloc  &&  performDealloc) {//对象需要被销毁
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);//发送消息调用dealloc销毁对象。
    }
复制代码

如果标志位都为YES调用objc_msgSend销毁对象。

3.refcntStorage结构事例

SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0)

 SIDE_TABLE_WEAKLY_REFERENCED(是否有弱引用)1,有0,没有
复制代码

SIDE_TABLE_DEALLOCATING (1UL<<1)

SIDE_TABLE_DEALLOCATING(是否要被销毁)1,被标记 0,不需要被销毁
复制代码

SIDE_TABLE_RC_ONE (1UL<<2)

SIDE_TABLE_RC_ONE添加引用计数的值左移两位想当于加4.
复制代码

SIDE_TABLE_RC_PINNED (1UL<<(WORD_BITS-1))

SIDE_TABLE_RC_PINNE(如果为1引用计数到达最大值)
复制代码
#ifdef __LP64__
#   define WORD_SHIFT 3UL
#   define WORD_MASK 7UL
#   define WORD_BITS 64//64位系统定义为64
#else
#   define WORD_SHIFT 2UL
#   define WORD_MASK 3UL
#   define WORD_BITS 32
#endif
复制代码

转载于:https://juejin.im/post/5c7f59f3e51d454f8a0c4f70

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值