ISA结构分析

了解对象

Objective-C是一门面向对象编程语言。对象是什么,我们这篇文章讲的isa和对象又有什么样的关系呢?
带着疑问我们可以去看看苹果开源源码。
在其中找到了对object的定义:

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

objc_object表示类的实例,就是我们通常说的对象。

LGPerson *objc = [[LGPerson alloc] init];
Class p1 = [objc class];
Class p2 = [LGPerson class];
打印结果p1:0x1000020f8  p2:0x1000020f8

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    ...
}

p1通过object_getClass获取到isa指向的类对象,p2通过类名也获取到一摸一样的对象。
从源码可以看到objc_class是继承自objc_object且其中也有isa。这是不是意味着类也是读对象。而且我们还可以得出一个结论类对象在内存中仅存在一份。

isa是什么

我们在研究对象初始化的时候,曾经跟随底层源码看到了其中有这么一段代码

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    ASSERT(!isTaggedPointer()); 
    if (!nonpointer) {
        isa = isa_t((uintptr_t)cls);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());
        isa_t newisa(0);
        ...
        isa = newisa;
    }
}
isa_t isa;

无论nonpointer条件YES还是NO,最终返回的都是isa_t类型的isa。我们继续去看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
};
__arm64__
#   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

ISA_BITFIELD中就是isa的数据结构定义。

  • nonpointer:表示是否对 isa 指针开启指针优化(0:纯 isa 指针;1:不止是类对象地址,isa中包含了类信息、对象的引用计数等)
  • has_assoc:关联对象标志位;0没有,1存在
  • has_cxx_dtor:该对象是否有 C++ 或者 Objc 的析构器(dealloc等),如果有析构函数,则需要做析构逻辑,如果没有,则可以更快的释放对象
  • shiftcls:存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位用来存储类指针。
  • magic:用于调试器判断当前对象是真的还是没有初始化的空间
  • weakly_referenced:指对象是否被指向或者曾经指向一个 ARC 的弱变量,没有弱引用的对象可以更快的释放。
  • deallocating:标志对象是否正在释放内存。
  • has_sidetable_rc:当对象引用计数大于 10 时,则需要借用该变量存储进位。(是否有外挂的散列表)
  • extra_rc:额外的引用计数;表示该对象的引用计数值,实际上是引用计数值减1。(eg:如果对象的引用计数为10,那么 extra_rc 为9。如果应用计数大于 10,则需要使用到 has_sidetable_rc)。

isa与类关联

对象可以通过isa获取到类信息,cls 与 isa 关联原理就是isa指针中的shiftcls位域中存储了类信息,我们可以通过以下方式验证:
1.我们通过断点,通过lldb调试看newisa.shiftcls赋值前后newisa的变化

赋值前
(lldb) p newisa
(isa_t) $0 = {
  cls = 0x001d800000000001
  bits = 8303511812964353
   = {
    nonpointer = 1
    has_assoc = 0
    has_cxx_dtor = 0
    shiftcls = 0
    magic = 59
    weakly_referenced = 0
    deallocating = 0
    has_sidetable_rc = 0
    extra_rc = 0
  }
}

赋值后
(lldb) p newisa
(isa_t) $1 = {
  cls = LGPerson
  bits = 8303516107940081
   = {
    nonpointer = 1
    has_assoc = 0
    has_cxx_dtor = 0
    shiftcls = 536871966
    magic = 59
    weakly_referenced = 0
    deallocating = 0
    has_sidetable_rc = 0
    extra_rc = 0
  }
}

在newisa.shiftcls = (uintptr_t)cls >> 3这一步之后,cls变成了LGPerson,bits中也只有shiftcls发生了变化,说明类的信息存入了shiftcls中。
2.通过 isa & ISA_MSAK
注意:

  • arm64中,ISA_MASK 宏定义值0x0000000ffffffff8ULL
  • x86_64中,ISA_MASK 宏定义值0x00007ffff
    在_class_createInstanceFromZone方法中,initIsa之后
(lldb) po obj


(lldb) x/4gx obj
0x100713e90: 0x001d8001000020f1 0x0000000000000000
0x100713ea0: 0x72616553534e5b2d 0x20646c6569466863
(lldb) po 0x001d8001000020f1 & 0x0000000ffffffff8ULL
LGPerson

(lldb) 

你可能感兴趣的:(ISA结构分析)