iOS基础类

isa指针

2022-03-01  本文已影响0人  苍眸之宝宝

简介:

  学习源码不看isa,估计只是学个寂寞,该篇文章是自己在阅读源码中的isa的理解。

源码和注释:

/// OC对象的基类
struct objc_object {
private:
    isa_t isa;
public:
    ...
}

/// isa联合体
union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    uintptr_t bits;

private:
    // Accessing the class requires custom ptrauth operations, so
    // force clients to go through setClass/getClass by making this
    // 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);
};

/// isa中结构体ISA_BITFIELD的宏定义
# if __arm64__  // arm64架构的isa
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
#   if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR  // arm64架构电脑M芯片的isa
#     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  // arm64架构手机A芯片的isa
#     define ISA_MASK        0x0000000ffffffff8ULL
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     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 unused            : 1;                                       \
        uintptr_t has_sidetable_rc  : 1;                                       \
        uintptr_t extra_rc          : 19
#     define RC_ONE   (1ULL<<45)
#     define RC_HALF  (1ULL<<18)
#   endif

# elif __x86_64__  // x86架构电脑intel芯片的isa
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_HAS_CXX_DTOR_BIT 1
#   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 unused            : 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的版本:

  1. 在64位前,isa就是一个普通的指针,存储这class对象、meta-class对象的内存地址,即Class cls
  2. 从64位后开始,对isa进行了优化,变成了一个联合体union,共占有8个字节,64位;这其中的三个变量clsbits、还有宏定义的结构体共用一块地址空间;
  3. 64位优化过的isa用不同的位域来存储不同的信息,不同位的信息可以通过位操作获取。

位代表的意义:
nonpointer
  0:代表普通的指针,存储着ClassMeta-Class对象的内存地址
  1:代表开启了64位优化,使用不同位域存储了不同信息
has_assoc
  是否有设置过关联对象,如果没有,释放时会更快
has_cxx_dtor
  是否有C++的析构函数,如果没有,释放时会更快
shiftcls
  存储着ClassMeta-Class对象的内存地址;这里也解释了&ISA_MASK才能取到ClassMeta-Class对象的内存地址
magic
  用于在调试时分辨对象是否完成初始化
weakly_referenced
  是否有被弱引用指向过,如果没有,释放时会更快
unused
  对象是否正在释放
extra_rc
  当表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么extra_rc为 9。如果引用计数大于 10, 则需要使用到下面的has_sidetable_rc
has_sidetable_rc
  0:引用计数存储在isaextra_r所占用位域中
  1:引用计数过大无法存储在isa中,引用计数存储在一个叫SideTable的类的属性中。

isa的初始化:

inline void 
objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
{ 
    ASSERT(!isTaggedPointer()); 
    
    isa_t newisa(0);

    if (!nonpointer) {
        newisa.setClass(cls, this);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());


#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信息识别:

代码:

    NSObject * obj = [[NSObject alloc] init];
    NSLog(@"1 isa_t = %p", *(void **)(__bridge void*)obj);
    self.objc = obj;
    NSObject * tmpObj = obj;
    NSLog(@"2 isa_t = %p", *(void **)(__bridge void*)obj);
    __weak typeof(obj) weakRefObj = obj;
    NSLog(@"3 isa_t = %p", *(void **)(__bridge void*)obj);
    objc_setAssociatedObject(obj, "attachKey", @[@1, @2], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    NSLog(@"4 isa_t = %p", *(void **)(__bridge void*)obj);

打印信息:

1 isa_t = 0x1a206aa3259
2 isa_t = 0x41a206aa3259
3 isa_t = 0x45a206aa3259
4 isa_t = 0x45a206aa325b

分析,64位苹果A芯片架构,高位不足补0:
分析打印中1的isa指针信息:

     高位                        <-                          低位
     ... 0001 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
     有上述讲解,从低位到高位:
     第一位nonpointer位,1表示优化过的isa
     第二位has_assoc位,0表示该对象没有关联对象
     第三位has_cxx_dtor位,0表示该对象没有C++析构函数
     第4-36位shiftcls位,类对象和元类对象地址信息,可以通过位运算获得
     第37-42位magic位,
     第43位weakly_referenced位,0表示没有弱引用
     第44位unused位,0表示没有正在释放
     第45位has_sidetable_rc位,0表示没有用SideTable存储引用计数
     第46-64位has_sidetable_rc位,0表示新创建的对象,引用计数位 0 + 1 = 1

分析所有isa指针信息:

        高位                        <-                             低位
     1  ... 0000 0001 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
     2  ... 0100 0001 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
     3  ... 0100 0101 1010 0010 0000 0110 1010 1010 0011 0010 0101 1001
     4  ... 0100 0101 1010 0010 0000 0110 1010 1010 0011 0010 0101 1011
     
     对比:
     1.第一位为1,都是64位nonpointer优化后的isa
     2.4中打印的第二位为1,表示有关联对象,其它为0没有关联对象
     3.第三位都为0,说明对象没有C++析构函数
     4.4-36位isa都相同,同一个实例对象指向的类地址码相同
     5.37-42位magic位debug调试位
     6.43位,1和2为0,3和4为1,因为1和2时对象没有弱引用,3和4对象被弱引用了
     7.44位都为0,表示对象没有正在释放操作
     8.45为为0,表示没有用SideTable存储引用计数
     9.46-64位,2、3和4打印的47位为1,表示引用计数为 2 + 1 = 3,1为0表示在1是为创建对象引用计数为 0 + 1 = 1
上一篇下一篇

猜你喜欢

热点阅读