iOS Objective-C isa
1.isa简介
isa
是 Objective—C
对象alloc
的时候,伴随初始化生成的一个属性,通过查看源码可以得出isa
内部是一个联合体,存储着类的信息。
NSObject isa:
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "*Wobjc*interface*ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
调用alloc
时初始化isa
的代码(initIsa源码):
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
assert(!cls*>instancesRequireRawIsa());
assert(hasCxxDtor == cls*>hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
assert(!isTaggedPointer());
if (!nonpointer) {
isa.cls = cls;
} else {
assert(!DisableNonpointerIsa);
assert(!cls*>instancesRequireRawIsa());
isa_t newisa(0);
#if SUPPORT_INDEXED_ISA
assert(cls*>classArrayIndex() > 0);
newisa.bits = ISA_INDEX_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.indexcls = (uintptr_t)cls*>classArrayIndex();
#else
newisa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
// This write must be performed in a single store in some cases
// (for example when realizing a class because other threads
// may simultaneously try to use the class).
// fixme use atomics here to guarantee single*store and to
// guarantee memory order w.r.t. the class index table
// ...but not too atomic because we do't want to hurt instantiation
isa = newisa;
}
}
2. isa的结构
2.1 查看isa
struct objc_object {
private:
isa_t isa; // isa的类型为isa_t
`
`
`
}
2.2 isa_t(联合体)
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
};
2.2 ISA_BITFIELD(位域)
#if SUPPORT_PACKED_ISA
// extra_rc must be the MSB*most field (so it matches carry/overflow flags)
// nonpointer must be the LSB (fixme or get rid of it)
// shiftcls must occupy the same bits that a real class pointer would
// bits + RC_ONE is equivalent to extra_rc + 1
// RC_HALF is the high bit of extra_rc (i.e. half of its range)
// future expansion:
// uintptr_t fast_rr : 1; // no r/r overrides
// uintptr_t lock : 2; // lock for atomic property, @synch
// uintptr_t extraBytes : 1; // allocated with extra bytes
# 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
// SUPPORT_PACKED_ISA
#endif
2.3 结论
由上述源码可以得出isa是一个isa_t的联合体,其中包含cls类指针,或者 ISA_BITFIELD(位域)
uintptr_t 实质上是:typedef unsigned long uintptr_t; 长整形,占8个字节,64位,所以isa的位域也是64位。
3.每个位域参数所的功能含义
3.1 nonpointer
- 占用1位,表示是否对 isa 指针开启指针优化
- 0:纯isa指针;1:不止是类对象地址,isa 中包含了类信息、对象的引用计数等
- 可通过initIsa源码看出区别
3.2 has_assoc
- 占用1位,关联对象标志位,0没有,1存在
3.3 has_cxx_dtor
- 占用1位,该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象
3.4 shiftcls
- arm64占用33位,x86_64占用44位,存储类指针的值
3.5 magic
- 占用6位,用于调试器判断当前对象是真的对象还是没有初始化的空间
3.6 weakly_referenced
- 占用1位,标志对象是否被指向或者曾经指向一个 ARC 的弱变量,
- 没有弱引用的对象可以更快释放
3.7 deallocating
- 占用1位 标志对象是否正在释放内存
3.8 has_sidetable_rc
- 占用1位 当对象引用计数大于 10 时,则需要借用该变量存储进位
3.9 extra_rc
- arm64占用19位,x86_64占用8位
- 当表示该对象的引用计数值,实际上是引用计数值减 1
- 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。
4. 联合体和位域
isa
联合体共用内存,取联合体内的最大内存,里面(属性)互斥
位域就是定义几个位表示一些信息,节约内存,内存优化的一种
位段,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。
信息的存取一般以字节为单位。实际上,有时存储一个信息不必用一个或多个字节,例如,“真”或“假”用0或1表示,只需1位即可。在计算机用于过程控制、参数检测或数据通信领域时,控制信息往往只占一个字节中的一个或几个二进制位,常常在一个字节中放几个信息。(可以百度百科详细查看,上面的部分摘自百度百科)
例子:
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