iOS 引用计数实现原理(alloc,retain,release,retainCount,dealloc)
alloc
系统经过调用之后会调用到c函数calloc,但是此时并没有设置引用计数为1
retain
其实就是系统去引用计数表,也就是sideTables中去查找,sizeTable,通过当前对象的指针去获取,SideTable &table = SideTables()[this]
上篇文章有介绍过什么事sideTable,当找到sideTable之后,再获取引用计数size_t $refcntStorage = table.refcnts[this] refcntStorage += SIDE_TABLE_RC_ONE
,其实也是hash查找,size_t 就是 unsigned long,查找到之后在进行加法操作
release
和上面查找方式一样,只不过做减1操作 refcntStorage -= SIDE_TABLE_RC_ONE
retainCount
SideTable &table = sideTables()[this];
size_t refcnt_result = 1;
RefcountMap::iterator it = table.refcnts.find(this);
refcnt_resount+= it->second>>SIDE_TABLE_RC_SHIFT
其实就是结合 size_t refcnt_result 这个局部变量操作的,刚新 alloc 出来的对象,在引用计数表中是没有引用计数的,之所以 retainCount 能获取到1,就是上面的原因,refcnt_resount+= it->second>>SIDE_TABLE_RC_SHIFT。
dealloc
在调用dealloc 之后,会经过 _objc_rootDealloc(),到 rootDealloc(),然后判断是否可以释放?判断释放的条件比较关键
1.nonpointer_isa,判断是否为这个isa指针类型,是否为非指针型的isa,之前文章讲过
2.weakly_referenced,是否有弱引用
3.has_assoc,是否有关联对象
4.has_cxx_dtor,判断是否有C++实现或者arc的实现
5.has_sideTable_rc,引用计数是否在sideTable中有存储
如果有一个满足条件,调用 object_disponse(),再开始释放\
object_disponse() 实现:
先判断是否有C++实现,然后判断是否有关联对象,如果没有c++,也没有关联对象,则调用object_cxxDestruct()和_object_remove_assocaations
来分别释放,接下来会调用clearDeallocating
方法,在这个方法中会调用sidetable_calearDeallocationg() 和 weak_clear_no_lock()
两个方法,作用是指向该对象的弱引用指针置为nil,这就是为什么我们不需要再dealloc中将指向他的弱引用指针置为nil的原因,接下来会调用table.refcnts.erase()
,来进行引用计数的擦除操作,然后结束流程