原文链接
产生原因
在 2013 年 9 月,苹果推出了 iPhone5s,与此同时,iPhone5s 配备了首个采用 64 位架构的 A7双核处理器,
为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念。对于 64 位程序,引入 Tagged Pointer 后,相关逻辑能减少一半的内存占用,以及3 倍的访问速度提升,100倍的创建、销毁速度提升。
64位系统下 有些对象占用内存翻倍
假设我们要存储一个 NSNumber对象,其值是一个整数。正常情况下,如果这个整数只是一个 NSInteger的普通变量,那么它所占用的内存是与 CPU 的位数有关,在 32 位 CPU 下占 4个字节,在 64 位CPU 下是占 8 个字节的。而指针类型的大小通常也是与CPU位数相关,一个指针所占用的内存在 32 位 CPU 下为4 个字节,在 64 位 CPU 下也是8个字节。
TaggedPointer
原理和作用
为了改进上面提到的内存占用和效率问题,苹果提出了Tagged Pointer对象。由于 NSNumber、NSDate 一类的变量本身的值需要占用的内存大小常常不需要8个字节,拿整数来说,4 个字节所能表示的有符号整数就可以达到 20 多亿(注:2^31=2147483648,另外 1 位作为符号位),对于绝大多数情况都是可以处理的。
所以我们可以将一个对象的指针拆成两部分,一部分直接保存数据,另一部分作为特殊标记,表示这是一个特别的指针,不指向任何一个地址。
所以,引入了Tagged Pointer对象之后,64 位 CPU 下NSNumber 的内存图变成了以下这样:
关于taggedpointer
- Tagged Pointer是专⻔⽤来存储⼩的对象,例如NSNumber,NSDate等。
- Tagged Pointer指针的值不再是地址了,⽽是真正的值。所以,实际上它不再是⼀个对象了,它只是⼀个披着对象⽪的普通变量⽽已。所以,它的内存并不存储在堆中,也不需要malloc和free。
- 当指针不够存储数据时,就会使用动态分配内存的方式来存储数据。
- 在内存读取上有着3倍的效率,创建时⽐以前快106倍。
isa_t(uintptr_t value) : bits(value) { } 中,“:”的作用
位域位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
nonpointer
0
如果nonpointer为0,代表raw isa,也就是没有结构体的部分,访问对象的 isa 会直接返回一个指向 cls 的指针,也就是在 iPhone 迁移到 64 位系统之前时 isa 的类型。
1
如果为1,代表它不是指针,是已经优化的isa,关于类的信息存储在shiftcls中。