Runtime(8)--isa指针

isa指针

对象的isa指针,用来表明对象所属的类的类型。
但是如果isa指针仅表示类型的话,对内存显然也是一个极大的浪费。在arm64架构之前,isa就是一个普通的指针,存储着Class或者Meta-Class对象的内存地址。从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息。

首先我们来看下isa指针是怎么在一个对象中存储的。看下面runtime简化的源码

struct objc_object {
  private:
      isa_t isa;
 }
struct objc_class : objc_object {
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
}
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;

# if __arm64__  // arm64下isa需要用的操作 `位掩码`
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    struct {
        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;
#       define RC_ONE   (1ULL<<45)
#       define RC_HALF  (1ULL<<18)
    };
}

从代码中可以看出,我们所谓的isa指针,最后实际上落脚于isa_t的共用体结构(也叫做联合类型)共用体结构C语言中的一种类型,简单来说,就是一种n选1的关系。比如isa_t中包含有cls,bits, struct三个变量,它们的内存空间是重叠的。在实际使用时,仅能够使用它们中的一种,你把它当做cls,就不能当bits访问,你把它当bits,就不能用cls来访问。

补充
结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
联合体: 内部的变量公用同一个内存地址。这也就意味着当多个变量都进行赋值的时候,可能只有一个变量的地址有正确有效的。
结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。
共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
联合的作用在于,用更少的空间,表示了更多的可能的类型,虽然这些类型是不能够共存的。

将注意力集中在isa_t共用体上,我们该怎样理解它呢?

首先它有两个构造函数isa_t(), isa_t(uintptr_value), 这两个定义很清晰,无需多言。

然后它有三个数据成员Class cls, uintptr_t bits, struct 。 其中uintptr_t被定义为typedef unsigned long uintptr_t,占据64位内存。

关于上面三个成员, uintptr_t bitsstruct 其实是一个成员,它们都占据64位内存空间,之前已经说过,联合类型的成员内存空间是重叠的。在这里,由于uintptr_t bitsstruct 都是占据64位内存,因此它们的内存空间是完全重叠的。而你将这块64位内存当做是uintptr_t bits还是 struct,则完全是逻辑上的区分,在内存空间上,其实是一个东西。
uintptr_t bitsstruct 是一个东西的两种表现形式。

uintptr_t bits是用来使用 struct里是用来解释说明bits里的值分配和作用表示
struct内的位域 增加可读性 对bits解释说明 而说明的占位加起来不能超过外面的所代表的uintptr_t bits变量的字节大小。
struct内的nonpointer、has_assoc、has_cxx_dtor顺序没有任何意思,只是解释说在bits中什么位置占多少位表示什么意思
具体的所处的位置主要取决于在set、get的时候与负责哪个区域的位掩码进行的位操作运算。一般都是按照从低位到高位的,这里也是如此

实际上在runtime中,任何对struct 的操作和获取某些值,如extra_rc,实际上都是通过对uintptr_t bits 做位操作实现的。uintptr_t bitsstruct 的关系可以看做,uintptr_t bits 向外提供了操作struct 的接口,而struct 本身则说明了uintptr_t bits 中各个二进制位的定义。

理解了uintptr_t bitsstruct 关系后,则isa_t其实可以看做有两个可能的取值,Class clsstruct。如下图所示:

isa

isa_t作为Class cls使用时,这符合了我们之前一贯的认知:isa是一个指向对象所属Class类型的指针。然而,仅让一个64位的指针表示一个类型,显然不划算。

因此,绝大多数情况下,苹果采用了优化的isa策略,即,isa_t类型并不等同而Class cls, 而是uintptr_t bits

  • uintptr_t bits对于struct位域中,struct共占用64位,从低位到高位依次是nonpointerextra_rc。成员后面的:表明了该成员占用几个bit。成员的含义如下:
成员 含义
nonpointer 1bit 标志位。1(奇数)表示开启了isa优化,0(偶数)表示没有启用isa优化。所以,我们可以通过判断isa是否为奇数来判断对象是否启用了isa优化。
has_assoc 1bit 标志位。表明对象是否有关联对象。没有关联对象的对象释放的更快。
has_cxx_dtor 1bit 标志位。表明对象是否有C++或ARC析构函数。没有析构函数的对象释放的更快。
shiftcls 33bit 类指针的非零位。
magic 6bit 固定为0x1a,用于在调试时区分对象是否已经初始化。
weakly_referenced 1bit 标志位。用于表示该对象是否被别的对象弱引用。没有被弱引用的对象释放的更快。
deallocating 1bit 标志位。用于表示该对象是否正在被释放。
has_sidetable_rc 1bit 标志位。用于标识是否当前的引用计数过大,无法在isa中存储,而需要借用sidetable来存储。(这种情况大多不会发生)
extra_rc 19bit 对象的引用计数减1。比如,一个object对象的引用计数为7,则此时extra_rc的值为6。
isa_t.png

由上表可以看出,和对象引用计数相关的有两个成员:extra_rchas_sidetable_rc。iOS用19位的extra_rc来记录对象的引用次数,当extra_rc不够用时,还会借助sidetable来存储计数值,这时,has_sidetable_rc会被标志为1。

我们可以算一下,对于19位的extra_rc ,其数值可以表示2^19 - 1 = 524287。 52万多,相信绝大多数情况下,都够用了。

isa指针的读写逻辑模拟

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容