在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