iOS isa 引用计数管理

iOS isa 引用计数管理

之前文章提得到过在 arm64 之后,苹果对isa指针进行了优化,采用 共用体的方式,nopointer 的方式来管理 isa,也就是说,isa 指针不仅仅只存放地址,也存放着引用计数相关的东西,我们来看源码


   uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19

isa 指针的定义大概是这样的


1. nonpointer,0代表普通的指针,存储着class ,meta-class 对象的内存地址,1代表优化过,使用位域存储更多的信息。
2. has_cxx_dtor : 是否有 C++ 的析构函数,如果没有,释放的时候回更快
3. shiftcls,存储着 class ,meta-class 对象的内存地址信息。
4. magic:用于在调试时分辨对象是否未完成初始化
5. weakly_referenced:是否有被弱引用指向过,如果没有,释放时候会更快
6. deallocating 对象是否正在释放
7. extra_rc 里面存储的值是引用计数减一
8. has_sidetable_rc:引用计数是否过大无法存储在 isa 中,如果为1,那么引用计数会存储在一个叫 SideTable 的类的属性中。
9. has_assoc : 是否有设置过关联对象,如果没有,释放会更快



struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts;
    weak_table_t weak_table;
    }

我们来看下 SideTable 这个类,RefcountMap 存储着引用计数,是个散列表,根据一个 key 就可以找到对应的 value,

objc_object::rootRetainCount()
{
    if (isTaggedPointer()) return (uintptr_t)this;

    sidetable_lock();
    isa_t bits = LoadExclusive(&isa.bits);
    ClearExclusive(&isa.bits);
    if (bits.nonpointer) {
        uintptr_t rc = 1 + bits.extra_rc;
        if (bits.has_sidetable_rc) {
            rc += sidetable_getExtraRC_nolock();
        }
        sidetable_unlock();
        return rc;
    }

    sidetable_unlock();
    return sidetable_retainCount();
}


objc_object::sidetable_getExtraRC_nolock()
{
    assert(isa.nonpointer);
    SideTable& table = SideTables()[this];
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it == table.refcnts.end()) return 0;
    else return it->second >> SIDE_TABLE_RC_SHIFT;
}


retainCount

这个源码是获取 retainCount , 可以看到,如果是 tagged pointer 类型的,那么直接返回,什么事tagged pointer ,我之前文章也有说过,接下来,去拿到 isa ,isa.bits,就代表拿到 isa,首先看下是否为 非指针类型也就是优化过的 isa,如果是的话,那么久直接将 extra_rc + 1,也就是引用计数加一,如果 bits.has_sidetable_rc 为1,那么他的引用计数是存储在 SideTable 里面的,不是存储在 isa 中,从 方法中可以看到,是先从 SideTables里面穿进去一个 key,拿到 SideTable ,然后又拿到这个SideTable 的 refcnts,也就是那个存放引用计数的散列表,然后再出入一个 key ,拿到一个遍历器,然后进行位运算。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容