isa指针
2022-03-01 本文已影响0人
苍眸之宝宝
简介:
学习源码不看isa
,估计只是学个寂寞,该篇文章是自己在阅读源码中的isa的理解。
源码和注释:
/// OC对象的基类
struct objc_object {
private:
isa_t isa;
public:
...
}
/// isa联合体
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
uintptr_t bits;
private:
// Accessing the class requires custom ptrauth operations, so
// force clients to go through setClass/getClass by making this
// private.
Class cls;
public:
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
bool isDeallocating() {
return extra_rc == 0 && has_sidetable_rc == 0;
}
void setDeallocating() {
extra_rc = 0;
has_sidetable_rc = 0;
}
#endif
void setClass(Class cls, objc_object *obj);
Class getClass(bool authenticated);
Class getDecodedClass(bool authenticated);
};
/// isa中结构体ISA_BITFIELD的宏定义
# if __arm64__ // arm64架构的isa
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
# if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR // arm64架构电脑M芯片的isa
# define ISA_MASK 0x007ffffffffffff8ULL
# define ISA_MAGIC_MASK 0x0000000000000001ULL
# define ISA_MAGIC_VALUE 0x0000000000000001ULL
# define ISA_HAS_CXX_DTOR_BIT 0
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t weakly_referenced : 1; \
uintptr_t shiftcls_and_sig : 52; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
# else // arm64架构手机A芯片的isa
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_HAS_CXX_DTOR_BIT 1
# 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 unused : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
# endif
# elif __x86_64__ // x86架构电脑intel芯片的isa
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
# define ISA_HAS_CXX_DTOR_BIT 1
# 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 unused : 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
isa
的版本:
- 在64位前,
isa
就是一个普通的指针,存储这class
对象、meta-class
对象的内存地址,即Class cls
; - 从64位后开始,对
isa
进行了优化,变成了一个联合体union
,共占有8个字节,64位;这其中的三个变量cls
、bits
、还有宏定义的结构体共用一块地址空间; - 64位优化过的
isa
用不同的位域来存储不同的信息,不同位的信息可以通过位操作获取。
位代表的意义:
nonpointer
:
0:代表普通的指针,存储着Class
、Meta-Class
对象的内存地址
1:代表开启了64位优化,使用不同位域存储了不同信息
has_assoc
:
是否有设置过关联对象,如果没有,释放时会更快
has_cxx_dtor
:
是否有C++的析构函数,如果没有,释放时会更快
shiftcls
:
存储着Class
、Meta-Class
对象的内存地址;这里也解释了&ISA_MASK
才能取到Class
、Meta-Class
对象的内存地址
magic
:
用于在调试时分辨对象是否完成初始化
weakly_referenced
:
是否有被弱引用指向过,如果没有,释放时会更快
unused
:
对象是否正在释放
extra_rc
:
当表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么extra_rc
为 9。如果引用计数大于 10, 则需要使用到下面的has_sidetable_rc
。
has_sidetable_rc
:
0:引用计数存储在isa
的extra_r
所占用位域中
1:引用计数过大无法存储在isa中,引用计数存储在一个叫SideTable
的类的属性中。
isa的初始化:
inline void
objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
{
ASSERT(!isTaggedPointer());
isa_t newisa(0);
if (!nonpointer) {
newisa.setClass(cls, this);
} else {
ASSERT(!DisableNonpointerIsa);
ASSERT(!cls->instancesRequireRawIsa());
#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
# if ISA_HAS_CXX_DTOR_BIT
newisa.has_cxx_dtor = hasCxxDtor;
# endif
newisa.setClass(cls, this);
#endif
newisa.extra_rc = 1;
}
// 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 don't want to hurt instantiation
isa = newisa;
}
isa信息识别:
代码:
NSObject * obj = [[NSObject alloc] init];
NSLog(@"1 isa_t = %p", *(void **)(__bridge void*)obj);
self.objc = obj;
NSObject * tmpObj = obj;
NSLog(@"2 isa_t = %p", *(void **)(__bridge void*)obj);
__weak typeof(obj) weakRefObj = obj;
NSLog(@"3 isa_t = %p", *(void **)(__bridge void*)obj);
objc_setAssociatedObject(obj, "attachKey", @[@1, @2], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
NSLog(@"4 isa_t = %p", *(void **)(__bridge void*)obj);
打印信息:
1 isa_t = 0x1a206aa3259
2 isa_t = 0x41a206aa3259
3 isa_t = 0x45a206aa3259
4 isa_t = 0x45a206aa325b
分析,64位苹果A芯片架构,高位不足补0:
分析打印中1的isa指针信息:
高位 <- 低位
... 0001 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
有上述讲解,从低位到高位:
第一位nonpointer位,1表示优化过的isa
第二位has_assoc位,0表示该对象没有关联对象
第三位has_cxx_dtor位,0表示该对象没有C++析构函数
第4-36位shiftcls位,类对象和元类对象地址信息,可以通过位运算获得
第37-42位magic位,
第43位weakly_referenced位,0表示没有弱引用
第44位unused位,0表示没有正在释放
第45位has_sidetable_rc位,0表示没有用SideTable存储引用计数
第46-64位has_sidetable_rc位,0表示新创建的对象,引用计数位 0 + 1 = 1
分析所有isa指针信息:
高位 <- 低位
1 ... 0000 0001 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
2 ... 0100 0001 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
3 ... 0100 0101 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
4 ... 0100 0101 1010 0010 0000 0110 1010 1010 0011 0010 0101 1011
对比:
1.第一位为1,都是64位nonpointer优化后的isa
2.4中打印的第二位为1,表示有关联对象,其它为0没有关联对象
3.第三位都为0,说明对象没有C++析构函数
4.4-36位isa都相同,同一个实例对象指向的类地址码相同
5.37-42位magic位debug调试位
6.43位,1和2为0,3和4为1,因为1和2时对象没有弱引用,3和4对象被弱引用了
7.44位都为0,表示对象没有正在释放操作
8.45为为0,表示没有用SideTable存储引用计数
9.46-64位,2、3和4打印的47位为1,表示引用计数为 2 + 1 = 3,1为0表示在1是为创建对象引用计数为 0 + 1 = 1