iOS tagged pointer
2020-02-22 本文已影响0人
孙掌门
iOS tagged pointer
从 64bit 开始,苹果引入了 tagged pointer 计数,用于优化 NSNumber , NSDate , NSString 等小对象的存储,没有这个数据之前,NSNumber 等对象需要动态分配内存,维护引用计数,NSNumber 指针存储的是堆中NSNumber对象的地址值,而引入了这个计数之后,NSNumber 指针里面存储的数据是 : tag + data ,也就是直接将数据存储在指针中。这样做特别节省空间。如果这个数据特别大,指针存储不下这个数,那么会回复之前的方式,存储在堆区,然后指针存放堆区的地址。
dispatch_queue_t queue = dispatch_get_global_queue(0, 0 );
for (int i = 0 ; i < 10000; i ++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"%@",@"123sdfasfdas"];
});
}
上面会发生什么呢?答案是可能崩溃,因为我们是多线程同时方位name的set方法,那么的set方法好比
-(void)setName:(NSString *)name{
if (_name != name) {
[_name release];
_name = [name copy];
}
}
好比这样,多个线程有可能同时去 release,所以会崩溃
解决方案,可以加锁,在name设置前后去加锁。
如果改成这样呢?
dispatch_queue_t queue = dispatch_get_global_queue(0, 0 );
for (int i = 0 ; i < 10000; i ++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"%@",@"123"];
});
}
就是把一个长字符串变成一个短的字符创,这时候发现,没有崩溃。因为后一个指针为 tagged pointer 类型的,就不存在release的操作,值直接就存储再来指针的里面,直接取值就可以了,所以就不会崩溃,他就不是一个OC对象。
NSString *str = [NSString stringWithFormat:@"123"];
NSString *str1 = [NSString stringWithFormat:@"aefasfasdfasfdasf"];
NSLog(@"%@ %@",[str class],[str1 class]);
我们来打印下两个类
NSTaggedPointerString __NSCFString
可以看到 第一个类为 tagged pointer 类,也证明了我们的猜想。
其实源码里面是有判断的,当为mac 的时候 &1,当为ios的时候&(1<<63),所以 ios 最高有效位为1就为 tagged pointer 类型,mac 最低有效位为1就为tagged pointer