一、isa是什么?
通过我的前一篇文章。我们可以得出,isa是对象alloc的时候,伴随初始化的一个属性。 其内部是一个联合体,其中包含一些类的信息。
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
二、isa的初始化以及结构
查看initIsa源码:
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 don't want to hurt instantiation
isa = newisa;
}
}
点击isa查看:
private:
isa_t isa;
我们发现,isa其实是一个isa_t结构的对象,接着看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
};
ISA_BITFIELD不同环境下的定义:
# 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
得出结论:isa是一个isa_t结构的联合体,其中包含cls类指针,或者一个ISA_BITFIELD位域。
位域定义:
指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
三、isa内部位域各个参数的意义
-
nonpointer:表示是否对 isa 指针开启指针优化 。
0:纯isa指针,1:不止是类对象地址。(isa 中包含了类信息、对象的引用计数等 )
从initIsa那段代码中可以看出,底层会通过判断nonpointer参数,来初始化isa:
if (!nonpointer) { isa.cls = cls; } else {…} -
has_assoc:关联对象标志位,0没有,1存在
-
has_cxx_dtor:该对象是否有 C++ 或者 Objc的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象。
-
shiftcls: 存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位用来存储类指针。
-
magic:用于在调试时分辨对象是否完成初始化
-
weakly_referenced:标志对象是否被指向或者曾经指向一个 ARC 的弱变量, 没有弱引用的对象可以更快释放。
-
deallocating:标志对象是否正在释放内存
-
has_sidetable_rc:对象引用计数是否大于 10,大于10 时,则需要借用sideTable进行存储
-
extra_rc:表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。
四、isa的走位分析
1、验证类对象的第一个属性为isa
我们根据x86结构,对对象的第一个属性去掉低3位与高17位
return (Class)(isa.bits & ISA_MASK);
这段代码就是我们在调用object_getClass(id obj)时源码的处理。
2、分析isa的指向
得出结论:
isa指向:类对象->类->元类->根元类->根元类
来自苹果官方的图解:(图中虚线代表isa指向关系,实线代表类的继承关系。)