isa指针

作者: 苍眸之宝宝 | 来源:发表于2022-03-01 14:48 被阅读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
    

    相关文章

      网友评论

        本文标题:isa指针

        本文链接:https://www.haomeiwen.com/subject/qpplrrtx.html