NONPointer_isa 指针中存放与该对象内存相关的消息

苹果将ISA设计成了联合体,在ISA中存储了与该对象相关的一些内存信息,因为 并不需要64个二进制全部都用来存储指针
ISA 的结构

// x86_64 架构
struct {
    uintptr_t nonpointer        : 1;  // 0:普通指针,1:优化过,使用位域存储更多信息
    uintptr_t has_assoc         : 1;  // 对象是否含有或曾经含有关联引用
    uintptr_t has_cxx_dtor      : 1;  // 表示是否有C++析构函数或OC的dealloc
    uintptr_t shiftcls          : 44; // 存放着 Class、Meta-Class 对象的内存地址信息
    uintptr_t magic             : 6;  // 用于在调试时分辨对象是否未完成初始化
    uintptr_t weakly_referenced : 1;  // 是否被弱引用指向
    uintptr_t deallocating      : 1;  // 对象是否正在释放
    uintptr_t has_sidetable_rc  : 1;  // 是否需要使用 sidetable 来存储引用计数
    uintptr_t extra_rc          : 8;  // 引用计数能够用 8 个二进制位存储时,直接存储在这里
};

// arm64 架构
struct {
    uintptr_t nonpointer        : 1;  // 0:普通指针,1:优化过,使用位域存储更多信息
    uintptr_t has_assoc         : 1;  // 对象是否含有或曾经含有关联引用
    uintptr_t has_cxx_dtor      : 1;  // 表示是否有C++析构函数或OC的dealloc
    uintptr_t shiftcls          : 33; // 存放着 Class、Meta-Class 对象的内存地址信息
    uintptr_t magic             : 6;  // 用于在调试时分辨对象是否未完成初始化
    uintptr_t weakly_referenced : 1;  // 是否被弱引用指向
    uintptr_t deallocating      : 1;  // 对象是否正在释放
    uintptr_t has_sidetable_rc  : 1;  // 是否需要使用 sidetable 来存储引用计数
    uintptr_t extra_rc          : 19;  // 引用计数能够用 19 个二进制位存储时,直接存储在这里
};

这里的 has_sidetable_rc 和 extra_rc, has_sidetable_rc 表明了该指针是否引用了sidetable 散列表,之所以有这个选项,是因为少量的引用计数是不会直接存放在SideTables表中的,对象的引用计数会存放在extra_rc 中,当其被存满时,才会存入相应的SideTables 散列表中,SideTable 中有很多张SideTable,每个SideTable 也都是一个散列表,而引用计数表就包含在SideTable之中。

散列表 (引用计数表,弱引用表)
引用计数要么存放在isa 的 extra_rc 中,要么存放在引用计数表中,而引用计数表中包含在一个叫SideTable 的结构中,它是一个散列表,也就是哈希表。而SideTable又包含在一个全局的StripeMap的哈希映射表中,这个表的名字叫SideTables。

当一个对象访问SideTables 时:
1、首先会取得对象的地址,将地址进行哈希运算,与SideTables中的SideTabel的个数取余,最后得到的结果就是该对象所访问的SideTable
2、在取的SideTable 中RefcountMap 表中再进行一次哈希查找。找到该对象在引用计数表中对应的位置。
3、如果该对象存在对应的引用计数,则对其进行操作,如果没有对应的引用计数,则创建一个对应的size_t对象,其实就是一个uint类型的无符号整型。

弱引用表也是一张哈希表的结构,其内部包含了每个对象对应的弱引用表weak_entry_t,而weak_entry_t 是一个结构数组,其中包含的则是每一个对象弱引用的对象对应的弱引用指针。

你可能感兴趣的:(NONPointer_isa 指针中存放与该对象内存相关的消息)