美文网首页
isa的作用与内部结构(下)

isa的作用与内部结构(下)

作者: 嗯o哼 | 来源:发表于2020-04-15 11:17 被阅读0次

    一、回顾

    oc对象的本质的结构体,结构体内部存放了一个isa指针

    //OC
    @interface NSObject{
      Class isa; // 包含一个isa指针
    }
    // 对应的 C
    struct NSObject_IMPL{
      Class isa;
    }
    // isa 本质就是一个指向 objc_class 结构体的指针
    typedef struct objc_class *Class;
    typedef struct objc_object *id; // id万能指针的原因
    objc_class继承objc_object
    

    二、源码分析

    查看runtime源码发现 内部的isa是isa_t类型的

    struct objc_object {
    private:
        isa_t isa; // 此时的isa是isa_t类型的
    
    public:
        // ISA() assumes this is NOT a tagged pointer object
        Class ISA();
        // getIsa() allows this to be a tagged pointer object
        Class getIsa();
        ......
    }
    

    isa的作用与内部结构(上)文中提到isa & 一个掩码值之后,才获取到真正的对象的地址,说明isa不是一个单纯的十六进制数据,isa_t类型的isa就是我们真正要找的isa的类型

    isa_t的内部结构

    union isa_t { //union共用体
        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
    };
    

    ISA_BITFIELD 内部定义了很多成员

    #if SUPPORT_PACKED_ISA
    // 真机
    # 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;
          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;
          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
    
    

    整合到一起阅读

    union isa_t { //union共用体
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
        Class cls;
        uintptr_t bits; // 用于存放所有的数据(struct中的变量)
        struct{
          uintptr_t nonpointer        : 1;
          uintptr_t has_assoc         : 1;
          uintptr_t has_cxx_dtor      : 1;
          uintptr_t shiftcls          : 33;
          uintptr_t magic             : 6; 
          uintptr_t weakly_referenced : 1;
          uintptr_t deallocating      : 1;
          uintptr_t has_sidetable_rc  : 1;
          uintptr_t extra_rc          : 19
        }
    // nonpointer占1位、has_assoc占1位indexclas占15位
    // 他们是按位计算,在内存中一个字节=8位
    };
    

    union 是c语言中的共用体,它和结构体有非常类似的用法

    结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

    获取共用体中的值可以通过位运算
    按位与 & 同为1值为1,否则为0
    按位或 | 同为1或1和0的时候,值为1,否则为0 
    按位取反 ~ 1变为0,0变为1
    
     000111                                                                                                 
    &111111          通过按位与的运算,我们可以获取特定位置的值 
    -------
     000111
    
    如 00110101,我们获取第三位是什么值
     00110101
    &00000100              得出的结果为1
     00000100
    由此可见,通过一个固定的掩码值,我们就可以获取到共用体内指定位置中的值。
    //扩展定义,看源码的时候,会遇到这种情况
    1<<0 表示将1向左移0位 000001 》000001
    1<<1 表示将1向左移1位 000001 》000010
    1<<2 表示将1向左移2位 000001 》000100
    

    基本应用:如我们的控制器中有很多个BOOL变量的属性,我们就可以通过一个共用体来存放,获取不同值的时候,使用不同的掩码值,从而达到节省内存的作用
    一个BOOL变零占4个字节,而在共用体内只占了1位,具体的使用不做细节描述,不是本文的 主要内容。抽时间专门写一篇文章作为补充

    三、属性

    // 获取内存地址
    isa_t中 有一个shiftcls 长度为33位, 存放的就是地址 通过&一个掩码值,就可以获取shiftcls存放的值。
    

    各个属性的作用

    nonpointer : 
    0,代表普通的指针,存储着Class、Meta-Class对象的内存地址 
    1,代表优化过,使用位域存储更多的信息
    
    has_assoc:是否有设置过关联对象,如果没有,释放时会更快
    has_cxx_dtor:是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
    shiftcls:存储着Class、Meta-Class对象的内存地址信息
    magic:用于在调试时分辨对象是否未完成初始化
    weakly_referenced:是否有被弱引用指向过,如果没有,释放时会更快
    deallocating:对象是否正在释放
    has_sidetable_rc:引用计数器是否过大无法存储在isa中,如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
    extra_rc:里面存储的值是引用计数器减1
    

    注意:对象的引用计数器是存储在isa中,extra_rc 占19位,最大数255,如果过大,就无法继续存储,extra_rc减半,另一部分就存放到一个叫SideTable的类中

    四、总结

    1.isa不是一个普通的指针,可以分为指针型isa和非指针型isa
    2.指针型isa,isa的值代表Class的地址
    3.非指针型isa,isa的部分值代表Class的地址
    4.isa在内存是实际是 isa_t的一个共用体,内部存储着对象的很多信息

    思考:isa指向的objc_class 是c/c++的结构体,它包含了NSObject对象的所有信息,objc_class 内部结构是什么样的?
    

    isa的作用与内部结构(上)

    相关文章

      网友评论

          本文标题:isa的作用与内部结构(下)

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