iOS Objective-C isa简介

iOS Objective-C isa

1.isa简介

isaObjective—C 对象alloc的时候,伴随初始化生成的一个属性,通过查看源码可以得出isa内部是一个联合体,存储着类的信息。

NSObject isa:

@interface NSObject  {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "*Wobjc*interface*ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}

调用alloc时初始化isa的代码(initIsa源码):

inline void 
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
    assert(!cls*>instancesRequireRawIsa());
    assert(hasCxxDtor == cls*>hasCxxDtor());

    initIsa(cls, true, hasCxxDtor);
}

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 do't want to hurt instantiation
        isa = newisa;
    }
}

2. isa的结构

2.1 查看isa

struct objc_object {
private:
    isa_t isa; // isa的类型为isa_t
    `
    `
    `
}

2.2 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
};

2.2 ISA_BITFIELD(位域)

#if SUPPORT_PACKED_ISA

    // extra_rc must be the MSB*most field (so it matches carry/overflow flags)
    // nonpointer must be the LSB (fixme or get rid of it)
    // shiftcls must occupy the same bits that a real class pointer would
    // bits + RC_ONE is equivalent to extra_rc + 1
    // RC_HALF is the high bit of extra_rc (i.e. half of its range)

    // future expansion:
    // uintptr_t fast_rr : 1;     // no r/r overrides
    // uintptr_t lock : 2;        // lock for atomic property, @synch
    // uintptr_t extraBytes : 1;  // allocated with extra bytes

# 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

// SUPPORT_PACKED_ISA
#endif

2.3 结论

由上述源码可以得出isa是一个isa_t的联合体,其中包含cls类指针,或者 ISA_BITFIELD(位域)
uintptr_t 实质上是:typedef unsigned long uintptr_t; 长整形,占8个字节,64位,所以isa的位域也是64位。

3.每个位域参数所的功能含义

3.1 nonpointer

  • 占用1位,表示是否对 isa 指针开启指针优化
  • 0:纯isa指针;1:不止是类对象地址,isa 中包含了类信息、对象的引用计数等
  • 可通过initIsa源码看出区别

3.2 has_assoc

  • 占用1位,关联对象标志位,0没有,1存在

3.3 has_cxx_dtor

  • 占用1位,该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象

3.4 shiftcls

  • arm64占用33位,x86_64占用44位,存储类指针的值

3.5 magic

  • 占用6位,用于调试器判断当前对象是真的对象还是没有初始化的空间

3.6 weakly_referenced

  • 占用1位,标志对象是否被指向或者曾经指向一个 ARC 的弱变量,
  • 没有弱引用的对象可以更快释放

3.7 deallocating

  • 占用1位 标志对象是否正在释放内存

3.8 has_sidetable_rc

  • 占用1位 当对象引用计数大于 10 时,则需要借用该变量存储进位

3.9 extra_rc

  • arm64占用19位,x86_64占用8位
  • 当表示该对象的引用计数值,实际上是引用计数值减 1
  • 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。

4. 联合体和位域

isa
联合体共用内存,取联合体内的最大内存,里面(属性)互斥

位域就是定义几个位表示一些信息,节约内存,内存优化的一种
位段,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。
信息的存取一般以字节为单位。实际上,有时存储一个信息不必用一个或多个字节,例如,“真”或“假”用0或1表示,只需1位即可。在计算机用于过程控制、参数检测或数据通信领域时,控制信息往往只占一个字节中的一个或几个二进制位,常常在一个字节中放几个信息。(可以百度百科详细查看,上面的部分摘自百度百科)

例子:

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

你可能感兴趣的:(iOS Objective-C isa简介)