isa

之前的博客留了一个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; // defined in isa.h
};
#endif
};

上述源码中 isa_tunion 类型,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; /*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
# 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; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
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。

参考链接