其他分享
首页 > 其他分享> > OC之runtime(共用体)

OC之runtime(共用体)

作者:互联网

在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的地址

从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来

存储更多信息,在apple源码objc中找到isa的结构源码大抵如下:

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      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

经过注释整理后的代码如下:

union isa_t
{
    Class cls;
    uintptr_t bits;
    struct {
        // nonpointer
        // 1 代表普通的指针,存储着Class、Meta-Class对象的内存地址
        // 0 代表优化过,使用位域存储更多信息
        uintptr_t nonpointer        : 1;
        // has_assoc 是否有设置过关联对象、如果没有,释放时会更快
        uintptr_t has_assoc         : 1;
        // has_cxx_dtor 是否有C++的析构函数,如果没有释放会更快
        uintptr_t has_cxx_dtor      : 1;
        // shiftcls 存储着Class、Meta-Class对象的内存地址信息
        uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/
        // magic 用于在调试时分辨对象是否未完成初始化
        uintptr_t magic             : 6;
        // weakly_referenced 是否有被弱引用指向过,如果没有,释放时会更快
        uintptr_t weakly_referenced : 1;
        // deallocating 对象是否正在被释放
        uintptr_t deallocating      : 1;
        // has_sidetable_rc 引用计数器是否过大无法存储在isa中,如果是1,引用计数将被存储到SideTable的类的属性中
        uintptr_t has_sidetable_rc  : 1;
        // extra_rc 里面存储的值是引用计数器减1
        uintptr_t extra_rc          : 19
    }
}

从源码中可以找到isa地址的方式:

#if SUPPORT_NONPOINTER_ISA

inline Class
objc_object::ISA()
{
    ASSERT(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    // define ISA_MASK        0x0000000ffffffff8ULL
    return (Class)(isa.bits & ISA_MASK);
#endif
}

从上面代码可以看出,arm64真机条件下isa.bits & 0x0000000ffffffff8ULL 就是类的地址,而且地址后三位永远为0

标签:存储,uintptr,ISA,OC,rc,共用,isa,runtime,Class
来源: https://www.cnblogs.com/muzichenyu/p/14238683.html