一、含义
- iOS 是在 64bit 开始,引入的
Tagged Pointer
技术 - 用于优化
NSNumber
、NSDate
、NSString
等 小对象 的存储- 比如: 小型的
OC 对象
,就可能用Tagged Pointer
来实现
- 比如: 小型的
- 在没有使用之前,
NSNumber
等对象就是一个普通的OC 对象。需要动态分配内存、维护引用计数等,NSNumber
指针存储的是堆中NSNumber
对象的地址值(跟其他的OC 对象
没有任何区别)- 例如:
NSNumber *number = [NSNumber numberWithInt: 10];
NSNumber * number = @(10);
NSNumber * number = @10;
- 这三种写法 是等价的。
- 例如:
- 使用之后,
NSNumber
指针里面存储的数据变成了 :Tag + Data
, 也就是将数据直接存储在了指针中Tag
: 标记,标记是NSNumber
类型还是 NSDate 类型等Data
: 真正的数据
- 当对象指针的最低有效位是1,则该指针为
Tagged Pointer
- 当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
Objc_msgSend
能够识别Tagged Pointer
, 比如NSNumber
的intValue
方法, 直接从指针提取数据,节省了以前的调用开销。
二、解释 NSNumber 未使用 tagged Pointer 之前的内存
如图:NSNumber * number = @10;
是定义在 main 函数中的,所以是 局部变量。在函数中定义的局部变量放在 栈空间。
- 如果
NSNumber
对象 的堆地址为 0x000001 - 那么 栈空间内的
number
存储的就是 0x00001
也就是说:如果想要将 10 这个值存储到系统中:
- 首先要:
alloc
一块 对空间 - 在弄一个 指针变量
NSNumber *number
- 在把
alloc
出来的堆内存空间地址给number
指针
如果用 int 类型
的话,才4个字节
。但是到了 NSNumber
就这么复杂。
* int a = 10 ;
那么为什么要包装成 NSNumber
类型?
- 因为
NSArray
和NSDictionary
中不能存储int
类型。所以只能包装成NSNumber
类型。 *number
指针要8个字节alloc
出来的对象最少要16个字节- 这样比
int
类型要多很多 - 所以苹果 引进了
tagged Pointer
这个技术
三、解释 NSNumber 使用 tagged Pointer 之后的内存
这个里面,相当于只用了8个字节,就保存了 值
例如:
打印结果是:
0x127,0x227,0x327
打印结果是:
0x427,0x527,0x627
如果存储的数很大
NSNumber *number = @(0xFFFFF);
NSLog(@"%p", number);
打印结果:0x102b292d0
这个地址很明显是一个堆空间的地址
也就是说:如果 tagged pointer 8 个控件放不下的话。就变成了堆空间地址。
五、Objc_msgSend
能够识别 Tagged Pointer
NSNumber *number1 = @4
// 运行时是 objc_msgSend(number1, @selector(intValue))
int a = [number1 intValue];
objc_msgSend(number1, @selector(intValue))
这句话的意思大家都知道。就是:通过number1
的isa
指针找到number1
的类对象,去它的类对象里面找intValue
方法。- 但是
number1
是采用tagged pointer
技术实现的。没有经过alloc
也就没有堆空间,也不存在isa
。因为tagged pointer
就一个指针,指针里面存储的东西就是tag + data
objc_msgSend
方法里面会 进行判断,有没有使用 tagged pointer
技术,如果有使用,就不会再去 拿 isa
在找东西。
- 它会 直接把 值从 指针中抽取出来。