小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
在探索alloc底层的时候,我们发现initInstanceIsa函数是其核心方法之一,它负责将class与isa进行关联,所以我们来探索一下initInstanceIsa的源码
inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor) {
ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
继续探索initIsa函数
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;
newisa.has_cxx_dtor = hasCxxDtor;
newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
newisa.bits = ISA_MAGIC_VALUE;
# if ISA_HAS_CXX_DTOR_BIT
newisa.has_cxx_dtor = hasCxxDtor;
# endif
newisa.setClass(cls, this);
#endif
newisa.extra_rc = 1;
}
isa = newisa;
}
可以发现这段函数有以下内容:
- 初始化
isa_t - 非
nonpointer,直接设置class - 否则,对
bits赋值,关联类信息 找到SUPPORT_INDEXED_ISA的定义:
#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
- 条件判断,默认为
# define SUPPORT_INDEXED_ISA 1的分支
isa_t联合体
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
uintptr_t bits;
private:
Class cls;
public:
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD;
};
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_t的源码分析,可以发现:
isa_t为联合体- 有
bits和cls两个成员变量,它们是互斥的 ISA_BITFIELD:isa结构 通过对源码的阅读我们可以知道以下isa的结构
# if __arm64__
# if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
# 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
# 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__
# 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结构的分析发现
- 不同
CPU结构,isa结构略有差异 - __has_feature:编译器是否支持该功能
ptrauth_calls:arm64e架构,引入指针验证代码(PAC)- 用于检测和防止内存中指针的意外更改
- 支持
Apple A12或更高版本A系列处理器的设备(如:XS/XS MAX/XR) - 详情可见:官方文档
TARGET_OS_SIMULATOR:判断是否为模拟器
通过对isa结构的分析可以得出以下isa位图
arm64位图
x86_64位图
nonpointer:表示是否对isa指针开启指针优化。0:纯isa指针,1:不止是类对象地址,isa中包含了类信息、对象的引用计数等。has_assoc:关联对象标志位。0:不存在,1:存在has_cxx_dtor:该对象是否有C++或者Objc的析构器。如果有析构函数,则需要做析构逻辑。如果没有,则可以更快的释放对象shiftcls:存储类指针的值。开启指针优化的情况下,在arm64架构中,有33位用来存储类指针magic:用于调试器判断当前对象是真的还是没有初始化的空间weakly_refrenced:标志对象是否被指向或者曾经指向一个ARC的弱变量,没有弱引用的对象可以更快释放deallocating:标志对象是否正在释放内存has_sidetable_rc:当对象引用计数大于10时,则需要借用该变量存储进位extra_rc:表示该对象的引用计数值,实际上是引用计数值减1.例如,如果对象的引用计数位10,那么extra_rc为9,如果引用计数大于10,则需要用到下面的has_sidetable_rc
结论:
- isa使用联合体+位域的方式存储,优化内存空间
- 类型分为
nonpointer和非nonpointer - 非
nonpointer只存储指针地址,nonpointer还存储类的其他信息