OC底层探索:ISA

446 阅读2分钟

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

什么是ISA

指向该对象为实例的类定义的指针,isa在源码中定义是一个结构体


typedef struct objc_class *Class;

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

struct objc_class: objc_object {
...
}

Class isa

可以看出isa就是objc_class *类型,也就是一个指针,指针类型占用8字节

初始化isa

inline void 
objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
{ 
     /* 判断是否是 TaggedPointer
     inline bool 内联函数
     objc_object::isTaggedPointer() 
     {
      return _objc_isTaggedPointer(this);
     }
     _objc_isTaggedPointer(const void * _Nullable ptr) 
     {
       // 对象的指正地址 & _OBJC_TAG_MASK == _OBJC_TAG_MASK
       // ARM64 / X86_64 _OBJC_TAG_MASK (1UL<<63)
       // i386 _OBJC_TAG_MASK 1UL, 最后一位是否为1
      return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
     }
    */
    ASSERT(!isTaggedPointer()); 
    
    // 初始化 一个 isa_t
    isa_t newisa(0);
    
    // 是否为nonpointer
    if (!nonpointer) {
        // 类的isa 
        newisa.setClass(cls, this);
    } else {
       // instance 的isa
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());


// isa_t 赋值
#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的内存结构

isa_t是一个联合体,联合体特性是公用一块内存,内部变量的是互斥的,意思是给一个变量赋值,其他变量则没有值

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

private:
    // 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);
};

image.png

# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e. 
M1 模拟器
#   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  掩码 取shiftcls 存的是类
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     define ISA_BITFIELD                                                      \
        uintptr_t nonpointer        : 1;    // 表示是否对 isa 指针开启指针优化
                                               0:纯isa指针,
                                               1:不⽌是类对象地址, isa 中包含了类
                                               信息、对象的引⽤计数等
                                 \
        uintptr_t has_assoc         : 1;   // 关联对象标志位,0没有,1存在                                    \
        uintptr_t has_cxx_dtor      : 1;   // 该对象是否有 C++ 或者 Objc 的析构器,                                               如果有析构函数,则需要做析构逻辑, 
                                              如果没有,则可以更快的释放对象                                   \
        uintptr_t shiftcls          : 33; // 存储类指针的值。开启指针优化的情况下
                                             在 arm64 架构中有 33 位⽤来存储类指针
        uintptr_t magic             : 6;  // 用于调试器判断当前是真的对象还是未初始化的空间                                    \
        uintptr_t weakly_referenced : 1;  // 是否是弱引用,                                   \
        uintptr_t unused            : 1;   //  是否使用过                                 \
        uintptr_t has_sidetable_rc  : 1;   //   当引用计数大于10,存储进位                                  \
        uintptr_t extra_rc          : 19   // 存储对象的引用计数,实则为 引用计数-1, 大于10,存到 has_sidetable_rc 中
#     define RC_ONE   (1ULL<<45)
#     define RC_HALF  (1ULL<<18)
#   endif

可以看出对象的isa[4~37]存的是class

通过lldb探索isa

创建一个对象打上断点

image.png

对象的isa

image.png

  • 根据上面的打印可以看出,isa(-->) 对象-->类-->元类-->根元类-->根元类
  • 类的isa 存到的就是元类,不需要通过mask掩码去得到,只有对象的才是 nonpointer。因为只有对象才有引用计数,弱引用等
  • 也可以得出其实类也是一个是对象,这也应证万物接对象

teacher是继承person, 通过lldb查看一下tacherisa image.png

  • 可以得出teacher元类也是指向根元类

继承关系的isa

image.png

  • -> 表示继承 meta 表示元类
  • WLWTeacher -> WLWPerson -> NSObject -> nil
  • WLWTeacher(meta) -> WLWPerson(meta) -> NSObject(meta) -> NSobject -> nil
  • 元类也是有继承的关系的,会继承父类的元类,值到根元类
  • 根元类的继承根类

NSProxy 的isa与继承

image.png

  • NSProxy是遵守NSObject协议的,也是根类,所以他跟NSOject根类一样,只是根类换成的NSProxy
  • 所以NSProxyNSObjec是同级的,都是根类

苹果官方

image.png

总结

  • 万物皆对象,类只有一块地址,相当于系统帮你创建了一个单例对象,然后我们基于类这个对象继承再开辟的新的内存创建对象
  • 元类也有继承关系,元类继承父类的元类
  • 根元类继承根类,根类继承nil