美文网首页
runtime中isa详解

runtime中isa详解

作者: SwiftUI | 来源:发表于2020-03-25 18:54 被阅读0次

什么是isa?

都说Objective-C是一门动态语言,为什么可以做到动态性呢?这其实跟isa有很大的关系,在程序运行的时候,你可以通过修改一个实例对象的isa来改变这个对象的类型,也可以通过isa来给一个类动态添加方法,对象调用方法也离不开isasuperclass等等。

在iPhone 5s之前,苹果的A系列处理器是32位的,从此A7之后都是64位的。然后对应着代码里面的变化是,指针从4个字节变到8个字节。苹果为了提高性能,对isa做了很大的调整。

32位版本的ojbc源码isa定义:

struct objc_object {
private:
    uintptr_t isa;

    //后面得代码省略
}

typedef unsigned long           uintptr_t;

64位版本的objc源码isa定义:

struct objc_object {
private:
    isa_t isa;

    //后面得代码省略
}

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

# 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


#if SUPPORT_INDEXED_ISA

# if  __ARM_ARCH_7K__ >= 2  ||  (__arm64__ && !__LP64__)
    // armv7k or arm64_32

#   define ISA_BITFIELD                         \
      uintptr_t nonpointer        : 1;          \
      uintptr_t has_assoc         : 1;          \
      uintptr_t indexcls          : 15;         \
      uintptr_t magic             : 4;          \
      uintptr_t has_cxx_dtor      : 1;          \
      uintptr_t weakly_referenced : 1;          \
      uintptr_t deallocating      : 1;          \
      uintptr_t has_sidetable_rc  : 1;          \
      uintptr_t extra_rc          : 7

// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa 
// field as an index into a class table.
// Note, keep this in sync with any .s files which also define it.
// Be sure to edit objc-abi.h as well.
#if __ARM_ARCH_7K__ >= 2  ||  (__arm64__ && !__LP64__)
#   define SUPPORT_INDEXED_ISA 1
#else
#   define SUPPORT_INDEXED_ISA 0
#endif

很明显,在32位的时候,isa就是一个普通指针,指向class或者meta-class;在64位时,isa就是一个共用体union了,里面有一个结构体,把8个字节64位分别作了不同的定义和用途。

  • nonpointer占1位,0表示普通指针,存储着class或meta-class的内存;1表示优化过,使用位域存储着更多的信息。
  • has_assoc占1位,表示是否设置过关联对象。
  • has_cxx_dtor占1位,表示是否有c++析构函数。
  • shiftcls占33位,存储着class或meta-class的内存地址。
  • magic占6位,用于调试时分辨对象是否未完成初始化。
  • weakly_referenced占1位,表示是否被弱引用指向过。
  • deallocating占1位,表示对象是否正在释放。
  • has_sidetable_rc占1位,如果为1,引用计数会存储在SideTable中。
  • extra_rc占19位,存储着引用计数减1。

如何获取isa指针?

通过ISA_MASK(0x0000000ffffffff8ULL)补码跟isa位域与运算可以得到,由于低地址的三位是0,所以class或meta-class的十六进制表示的地址最后一位要么是8(0x******8)要么是0(0x******0)

inline Class 
objc_object::ISA() 
{
    assert(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    return (Class)(isa.bits & ISA_MASK);
#endif
}

为什么要有isa?

image.png

isa用来连接实例对象,类对象,元类对象之间的关系。isa中包含了对象的引用计数等核心信息。

  • oc中方法的调用,消息机制objc_msgSend需要使用isasuperclass来完成。
  • kvo的实现需要改变被观察者的类型,需要修改isa来完成。
  • 实例对象的释放,需要用到isa中存储的引用计数来完成。

相关文章

网友评论

      本文标题:runtime中isa详解

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