美文网首页runtime
三、iOS中的isa

三、iOS中的isa

作者: Fred丶Lee | 来源:发表于2019-12-23 00:34 被阅读0次

一、isa 是什么?

通过iOS源码alloc init new 分析
可以知道,对象通过alloc创建对象,分配内存,最后还调用了initInstanceIsa来初始化isa属性。Objective-C 对象在底层本质上是结构体,所有的对象都包含一个isa属性,用来关联对象和存储一些对象的信息。
isa 是对象中的第一个属性,因为这一步是在继承的时候发生的,要早于对象的成员变量,属性列表,方法列表以及所遵循的协议列表。

下面我们先看看initInstanceIsa实例方法点进来是什么

objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    assert(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa.cls = cls;
    } else {
        assert(!DisableNonpointerIsa);
        assert(!cls->instancesRequireRawIsa());

        isa_t newisa(0);

#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
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

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

函数一开始的 assert(!isTaggedPointer()); 是断言对象的指针不是 Tagged Pointer.
接下来就是对 isa 类型的判断 if (!nonpointer) { ... } else { ... },如果 isa 不是 nonpointer,也就是单纯的指针(Class 类型),则 isa 就直接被赋值为 cls。如果 isa 是 nonpointer,也就是 isa_t 类型的话,则先初始化一个所有位为 0 的指针 isa_t newisa(0)。

此时我们点进去看看isa_t是什么

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

然后在看看ISA_BITFIELD是什么

# 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; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      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)

• nonpointer: 表示是否对 isa 指针开启指针优化
• 0: 纯 isa 指针
• 1: 不止是类对象地址, isa 中包含了类信息、对象的引用计数等
• has_assoc: 关联对象标志位,0 没有,1 存在
• has_cxx_dtor: 该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象
• shiftcls: 存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位用来存储类指针。
• magic: 用于调试器判断当前对象是真的对象还是没有初始化的空间
• weakly_referenced: 标志对象是否被指向或者曾经指向一个 ARC 的弱变量,
没有弱引用的对象可以更快释放。
• deallocating: 标志对象是否正在释放内存
• has_sidetable_rc: 当对象引用技术大于 10 时,则需要借用该变量存储进位
• extra_rc: 当表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。

由此可以得知 isa_t是一个联合体/位域,联合体的特性就是内部所有的成员共用一块内存地址空间,也就是说isa_t、cls、bits会共用同一块内存地址空间,这块内存地址空间大小取决于最大长度内部成员的大小即64位8字节。由此我们可以知道isa 的所占的内存空间大小为8字节。

位域定义:
指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。

关于 SUPPORT_INDEXED_ISA 宏,它的定义是这样的:

// 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

这个ARM_ARCH_7K应该是对watchOS的一种处理,有兴趣的可以查一查。 这里我们直接看define SUPPORT_INDEXED_ISA 0的情况,所以直接看else分支里就可以了

  newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
  newisa.has_cxx_dtor = hasCxxDtor;
  newisa.shiftcls = (uintptr_t)cls >> 3;
  isa = newisa;

可以看到,先将 newisa 的 bits 赋值为常量 ISA_MAGIC_VALUE,里面包括了 magic 和 nonpointer 的值。然后将是否有 C++ 析构函数标示上,最后将位移(shift)后的 cls 存入 shiftcls(类指针按照 8 字节对齐,所以最后三位一定是 0,所以可以右移三位来节省位的使用)。

bits中的其他说明

  • has_assoc 对象含有或者曾经含有关联引用,没有关联引用的可以更快地释放内存
  • weakly_referenced 对象被指向或者曾经指向一个 ARC 的弱变量,没有弱引用的对象可以更快释放
  • deallocating 对象正在释放内存
  • has_sidetable_rc 当对象引用技术大于 10 时,则需要借用该变量存储进位。
  • extra_rc 表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。

二、isa走位分析

我们都知道Object-C的对象其本质就是结构体,前面我们也分析了每一个对象都会有一个isa。同时我们也知道了其实类的本质也是一个结构体,而且是继承自objc_object的。所以说每一个类也都有一个isa,接下就通过官方提供的isa走位图来看一下 isa走位图.png

然后我们通过代码来验证一下isa的走位


isa走位分析.png

相关文章

  • 三、iOS中的isa

    一、isa 是什么? 通过iOS源码alloc init new 分析可以知道,对象通过alloc创建对象,分配内...

  • iOS底层-isa结构(isa_t)

    在iOS 底层-- isa指向探究中探索了isa的指向,那么isa的结构具体是什么样的。从源码中来着手研究。 一、...

  • isa结构解析

    1. isa初始化 在 iOS alloc原理分析 中会 initInstanceIsa中初始化isa,源码如下:...

  • IOS - 64位中 isa 区域的变化

    原文链接 不再是指针的 isa 在 iOS arm64 的架构中,属于 Objective-C 对象的 isa 空...

  • ISA的结构详解

    一,isa 的作用 在iOS开发过程中,我们知道,任何一个对象都有一个isa,通过isa 指向,可以找到父类,以及...

  • iOS底层原理--类的结构分析

    在前一篇文章中,我们已经探讨了iOS底层原理--isa与类关联的原理,isa包含了Class类,从而将isa与Cl...

  • iOS Objective-C isa简介

    iOS Objective-C isa 1.isa简介 isa是 Objective—C 对象alloc的时候,伴...

  • iOS底层之isa走位探索

    前置文章: iOS底层之类的重要组成部分-isa结构体分析 前言 从上篇文章中我们得知对象的isa指针中的shif...

  • iOS中的isa指针

    什么是isa OC是一门面向对象的语言,每一个对象都是类的一个实例,在OC语言内部,每一个对象都有一个isa指针,...

  • iOS中的isa指针

    isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的...

网友评论

    本文标题:三、iOS中的isa

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