之前的博客留了一个64位CPU中isa指针的坑,今天来填个坑。
isa 的本质
回顾OC对象的本质,每个OC对象都含有一个isa指针,arm64
之前,isa仅仅是一个指针,保存着对象或类对象内存地址,在 arm64
架构之后,apple对isa进行了优化,变成了一个共用体 union
结构,同时使用位域来存储更多的信息。OC对象的isa指针斌不是直接指向类对象或者是元类对象的,而是需要 &ISA_MASK
通过位运算才能取到相应的地址,但是为什么要这样做。
objc_object
1 2 3 4 5
| struct objc_object { private: isa_t isa; ... }
|
isa_t
isa
指针其实是一个 isa_t
类型的共用体,我们看下 isa_t
内部查看其结构。
1 2 3 4 5 6 7 8 9 10 11 12
| union isa_t { isa_t() { } isa_t(uintptr_t value) : bits(value) { }
Class cls; uintptr_t bits; #if defined(ISA_BITFIELD) struct { ISA_BITFIELD; }; #endif };
|
上述源码中 isa_t
是 union
类型,union
表示共用体。可以看到共用体中有一个结构体,结构体内部分别定义了一些变量,变量后面的值代表的是该变量占用多少个字节,也就是位域。
位域
位域声明 位域名 : 位域长度
- 如果一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
- 位域的长度不能大于数据类型本身的长度,比如int类型就不能超过32位二进位。
- 位域可以无位域名,这时它只用来作填充或调整位置,无名的位域是不能使用的。
ISA_BITFIELD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| # 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; \ uintptr_t magic : 6; \ uintptr_t weakly_referenced : 1; \ uintptr_t deallocating : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 19 # define RC_ONE (1ULL<<45) # define RC_HALF (1ULL<<18)
# elif __x86_64__ # define ISA_MASK 0x00007ffffffffff8ULL # define ISA_MAGIC_MASK 0x001f800000000001ULL # define ISA_MAGIC_VALUE 0x001d800000000001ULL # define ISA_BITFIELD \ uintptr_t nonpointer : 1; \ uintptr_t has_assoc : 1; \ uintptr_t has_cxx_dtor : 1; \ uintptr_t shiftcls : 44; \ uintptr_t magic : 6; \ uintptr_t weakly_referenced : 1; \ uintptr_t deallocating : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 8 # define RC_ONE (1ULL<<56) # define RC_HALF (1ULL<<7)
# else # error unknown architecture for packed isa # endif
|
上面的代码描述了再64位下 arm64
架构和 x86_64
架构中的 isa
的占用空间布局。
isa中存储的信息及作用
- nonpointer:0代表一个普通指针,储存着Class、Meta-Class对象的内存地址。1代表优化后的使用位域储存更多的信息的结构体。
- has_assoc:表示是否有设置过关联的对象,如果没有,释放时候会更快。
- has_cxx_dtor:表示是否有声明C++析构函数,如果没有释放会更快。
- shiftcls:这里存储着Class、Meta-Class对象的内存地址信息。
- magic:用于在调试时分辨对象是否未完成初始化。
- weakly_referenced:表示是否有被弱引用指向过。
- deallocating:表示对象是否正在释放。
- has_sidetable_rc:引用计数器是否过大无法存储在isa中,如果为1,那么引用计数会存储在一个叫SideTable的属性中。
- extra_rc:里面存储的值是引用计数器减1。
参考链接