从64bit开始,iOS引入了Tagged Pointer技术,用于优化NSNumber、NSDate、NSString等小对象的存储
概述
以NSNumber为例,在没有使用Tagged Pointer之前,NSNumber等对象需要动态分配内存、维护引用技术等,NSNumber指针存储的是堆中的NSNumber对象的地址值
在使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了:Tag + Data,也就是将数据直接存储在了指针中
当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
objc_msgSend能识别Tagged Pointer,比如NSNumber的intValue方法,直接从指针提取数据,节省了以前的调佣开销
例
-
以下述为例,第二个for循环,会在执行的时候crash!
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); for (int i = 0; i < 1000; i++) { dispatch_async(queue, ^{ self.testString = [NSString stringWithFormat:@"abc"]; }); } for (int i = 0; i < 1000; i++) { dispatch_async(queue, ^{ self.testString = [NSString stringWithFormat:@"abcdefghijk"]; }); }
-
分析:
ARC的实现原理其实就是MRC,在MRC中,代码类似如下,由于上面的例子中,会异步调用 [_testString release] ,因此会导致提前release导致崩溃;// 模拟MRC - (void)setTestString:(NSString *)testString{ if (_testString == testString) { [_testString release]; // 赋值为新对象前,先释放旧对象 _testString = [testString copy]; } } - (NSString *)testString{ return _testString; } - (void)dealloc{ [_testString release]; _testString = nil; [super deallco]; }
-
那么为什么 if (_testString == testString) 没有拦截住呢?
是因为每次 [NSString stringWithFormat:@"abcdefghijk"] 时分配的地址都不一样! -
那么为什么 self.testString = [NSString stringWithFormat:@"abc"] 没有问题呢?
这就是 Tagged Pointer 的原因了!这里RunTime 判断到 Tagged Pointer 后直接进行赋值,而根本没有调用 set 方法(强调一下这里每次 [NSString stringWithFormat:@"abc"] 的值是一样的)
如何判断是否为 Tagged Pointer
翻阅RunTime源码,可以查找到 _objc_isTaggedPointer 方法,我们以OC的方式模拟实现如下:
// 如果是iOS平台 (指针的最 '高' 有效位是1,就是Tagged Pointer))
# define _OBJC_TAG_MASK (1UL<<63)
// 如果是Mac平台(指针的最 '低' 有效位是1,就是Tagged Pointer)
//# define _OBJC_TAG_MASK 1UL
BOOL isTaggedPointer(id pointer){
return ((uintptr_t)pointer & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
- (void)taggerPointerTest{
NSString *str = [NSString stringWithFormat:@"abcdefghijk"];
NSString *str1 = [NSString stringWithFormat:@"abc"];
NSLog(@"\nstr - %p: isTaggedPointer: %d\nstr1 - %p isTaggedPointer: %d",str,isTaggedPointer(str),str1,isTaggedPointer(str1));
}
str - 0x600002660500: isTaggedPointer: 0
str1 - 0x81a8f3dc8fa2ffae isTaggedPointer: 1