在ARM64操作系统下,一个指针占用64bit,但其实存储一个对象的地址32就够了。而且访问堆内存的效率比访问栈要慢。所以基于性能和内存使用效率,苹果推出了新的内存管理的功能。
我们知道,对象的定义为:
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
其中,将isa指针定义为private私有变量。是为了不让外部直接访问。
为什么不让访问呢?因为isa已经不再是一个堆内存对象的地址,而是一个union结构。
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
};
union的意思就是,可能是Class cls,也可能是uintptr_t bits,也可能是
struct {
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
}
那到底是什么呢?我们来看下获取isa的方法的实现。
inline Class objc_object::getIsa()
{
if (!isTaggedPointer()) return ISA();
uintptr_t ptr = (uintptr_t)this;
if (isExtTaggedPointer()) {
uintptr_t slot =
(ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
return objc_tag_ext_classes[slot];
} else {
uintptr_t slot =
(ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
return objc_tag_classes[slot];
}
}
可以看出,不是TaggedPoint时,使用的是ISA。当是TaggedPoint并且为ExtTaggedPointer,则按位操作,返回3~37字节的真实的对象的地址。当就是TaggedPoint且不为ExtTaggedPointer时,返回objc_tag_classes数组中的位置。