isa_t

作者: cmhfx1 | 来源:发表于2017-06-12 16:10 被阅读0次

代替 isa 指针的是结构体 isa_t

当实例方法被调用时,它要通过自己持有的isa 来查找对应的类,然后在object_class的 class_data_bits_t中查找对应方法的实现

objc-private.h  能翻出其定义

对于不支持优化的,isa_t共用体,我们用到的只有cls,也就是类指针,对于支持优化的,例如__x86_64__ ,iPhone5s等架构为 __arm64__,我们使用的是结构体,具体结构体的实现和位数可能有些差别,不过这些字段都是存在的。


我们可以通过 isa 初始化的方法 initIsa 来初步了解这 64 位的 bits 的作用:

inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)

{

initIsa(cls, true, hasCxxDtor);

}

inline void objc_object::initIsa(Class cls, bool indexed, bool hasCxxDtor)

{

    if (!indexed) {

         isa.cls = cls; 

    } else {

          isa.bits = ISA_MAGIC_VALUE;

          isa.has_cxx_dtor = hasCxxDtor;

          isa.shiftcls = (uintptr_t)cls >> 3;

     }

}

由于在 initInstanceIsa 方法中传入了 indexed = true,所以,我们简化一下这个函数的实现:

inline void objc_object::initIsa(Class cls, bool indexed, bool hasCxxDtor)

{

      isa.bits = ISA_MAGIC_VALUE;

      isa.has_cxx_dtor = hasCxxDtor;

      isa.shiftcls = (uintptr_t)cls >> 3;

}

#define ISA_MAGIC_VALUE 0x001d800000000001ULL

由于共用体的特性,对bits赋值,等价于对结构体赋值。0x0000000000000001ULL 64位二进制数,放入共用体变量空间。

我感觉这个uintptr_t,于大小端模式是有关系的,这也是疑惑。假设是,小端模式。

又因为,结构体首成员在低地址,尾成员在高地址。

在使用 ISA_MAGIC_VALUE 设置 isa_t 结构体之后,实际上只是设置了 indexed 以及 magic 这两部分的值。结构体其余成员均为0。(indexed= 1)

其中 indexed 表示 isa_t 的类型:

0 表示 raw isa,也就是没有结构体的部分,访问对象的 isa 会直接返回一个指向 cls 的指针,也就是在 iPhone 迁移到 64 位系统之前时 isa 的类型

1 表示当前 isa 不是指针,但是其中也有 cls 的信息,只是其中关于类的指针都是保存在 shiftcls 中。

magic 用于调试器判断当前对象是真的对象还是没有初始化的空间

isa.has_cxx_dtor = hasCxxDtor;

在设置 indexed 和 magic 值之后,会设置 isa 的 has_cxx_dtor,这一位表示当前对象有 C++ 或者 ObjC 的析构器(destructor),如果没有析构器就会快速释放内存。

isa.shiftcls = (uintptr_t)cls >> 3;

在为 indexed、 magic 和 has_cxx_dtor 设置之后,我们就要将当前对象对应的类指针存入 isa 结构体中了。

使用整个指针大小的内存来存储 类地址(cls)有些浪费,尤其在 64 位的 CPU 上。在 ARM 64 运行的 iOS 只使用了 33 位作为指针(与结构体中的 33 位无关,Mac OS 上为 47 位),而剩下的 31 位用于其它目的。类的指针也同样根据字节对齐了,每一个类指针的地址都能够被 8 整除,也就是使最后 3 bits 为 0,为 isa 留下 34 位用于性能的优化。苹果的ARM64运行时利用了一些很棒的性能改进

这一段话是什么意思呢?

64位CPU地址总线通常64根,表示的二进制数64位,也就是一个地址8个字节。无论是类地址,对象地址。但是呢,这64个字节并不是全部用到,没用到的高位补0,我们看以十六进制打印的类地址,有12*4=48,有9*4=36,我们肯定取48,但是48位的,最高位十六进制均为7,转为二进制位0111,也就是说,64位的有效位只有48-1=47位,其余高位补0。而ARM64上,类的地址有效位只有33位。

而且,地址是要内存对齐的,如64位八字节对齐(地址都能够被8整除),因此,这些有效位中,最低三位必然为0

因此,在isa中存储Class指针时右移三位是没有问题的。

我搜索到了一篇文章,是arm64 and you的译文  中有这么一段话:

尽管指针为64位,但在实际使用中,这些位数并不是都用上了。例如X86-64的Mac OS X系统仅使用了其中的47位。而ARM64上占用得更少,目前只有33位。只要未被系统全部占用,这些指针就能用于存储数据。这是Objective-C Runtime演进史上最重要的变化之一。

Objective-C对象是连续的内存块,这个内存块中第一个指针大小的部分称为ISA。一般来说,ISA是一个指向该对象所属类的指针。不过这么大的空间仅作为指针有点儿浪费,尤其是在64位CPU上。运行iOS的ARM64目前仅使用了一个指针的33位,而其余31位则另作他用。另外,类 指针还需要对齐,这就释放了另外3位,于是ISA指针中共有34位可另作他用。苹果的ARM64 Runtime正是利用了这一点使性能有了大幅提升。

相关文章

  • isa_t

    代替 isa 指针的是结构体 isa_t 当实例方法被调用时,它要通过自己持有的isa 来查找对应的类,然后在ob...

  • isa_t

    objc_object中,第一个成员变量就是isa_t isa,也就是说所有的对象都包含一个类型为isa_t的变量...

  • iOS - isa、class-rw-t、class-ro-t结

    源码objc-private.h中 isa_t ISA_BITFIELD 上面联合体 isa_t 涉及到一个位域的...

  • iOS内存管理及ARC相关实现学习

    1. 对象与类 1.1 对象 对象(Class或id)内部只有一个isa_t联合体指针。isa_t联合体内部只有两...

  • isa详解-位域

    ``` union isa_t { Class cls; uintptr_t bits; Str...

  • 结构体 isa_t

    在本章中,我们从NSObject的定义出发,了解了OC中类和对象所对应的数据结构objc_class和objc_o...

  • runtime中objc_object内部结构解析

    新版的objc_object中 struct objc_object { isa_t isa; } 在构建对象时...

  • 01Runtime之总体概括正式

    是是是 runtime.hmessage.h 类结构 改为 64 位之后的优势 isa_t构成

  • iOS RunTime

    Runtime 一、数据结构 1、objc_object id = objc_object : isa_t为共用体...

  • Runtime

    一、id(objc_object,isa id=objc_object(isa_t,isa操作相关,弱引用相关,关...

网友评论

      本文标题: isa_t

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