iOS中 Tagged Pointer 技术
前言:从64位开始,iOS引入了Tagged Pointer技术,用于优化NSNumber、NSDate、NSString等小对象的存储。
Tagged Pointer主要为了解决两个问题:
[*]内存资源浪费,堆区需要额外的开辟空间
[*]访问效率,每次set/get都需要访问堆区,浪费时间, 而且需要管理堆区对象的声明周期,降低效率
Tagged Pointer特点:
[*]专门用来存储小对象,比如NSString,NSNumber,NSDate
[*]Tagged Pointer指针的值不再是堆区地址,而是包含真正的值。所以它不会在堆上再开辟空间了,也不需要管理对象的生命周期了。
[*]内存读取提升3倍,创建比之前快100多倍,销毁速度更快
一、引入Tagged Pointer 前后对比
1、引入前
NSNumber等对象需要动态分配内存、维护引用计数等。 总共的空间= 指针空间 + 堆中分配的空间
2、引入后
NSNumber等对象,只需要分配一个指针即可,这个指针内部会包含这些数据内容。
总空间 = 指针空间
因为不用去用对象的方式管理引用计数,所以省却了 retain,release操作。
二、Tagged Pointer 原理
number1只有栈上的指针内存;而maxNum不仅有指针内存,在堆中还分配了32字节的内存用于存储该变量的值。通过观察发现,对象的number1、number2、number3、number4都存储在了对应的指针中;而maxNum不同由于数据过大,导致无法 1 个指针 8 个字节的内存根本存不下,而申请了32字节堆内存。
[*]NSString类型的Tagged Pointer指针与基本类型的指针是不一样的,末尾的数字为字符串的长度;
[*]NSString类型的Tagged Pointer指针存储char类型,返回的是ASCII码(该值为16进制的,需要进行十进制转换)
三、如何判断是否使用了 Tagged Pointer 技术
BOOL isTaggedPointer(id pointer) {
return (long)(__bridge void *)pointer & 1;
}
该函数就是调用了isTaggedPointer。
四、使用 Tagged Pointer 注意点
我们知道,所有OC对象都有isa指针,而Tagged Pointer并不是真正的对象,它没有isa指针,所以如果你直接访问Tagged Pointer的isa成员的话,在编译时将会有警告。
五、面试题
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
self.name = ;
});
}
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
self.name = ;
});
}
两者运行结果有何不同?
首先看self.name = ;
崩溃,并且崩溃在objc_release的地方。
是什么原因导致崩溃的呢?
我们知道,
self.name = ;
其实是调用了
];
而setName:的实现是:
- (void)setName:(NSString *)name
{
if (_name != name) {
;//老的释放掉
_name = ;//传入的值copy后赋值给_name
}
}
由于是async异步操作,self.name = ;即;有可能会被多条线程同时操作。导致,线程n把_name释放掉,线程n+1又要执行_name的释放,从而造成_name已经被释放两次,第二次访问的时候,_name已经释放过,造成坏内存访问。
解决方法一:atomic
@property (copy, atomic) NSString *name;
从而:
- (void)setName:(NSString *)name
{
//加锁操作
if (_name != name) {
;
_name = ;
}
//解锁操作
}
解决方法二:
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i<1000; i++) {
dispatch_async(queue, ^{
//加锁
self.name = ;
});
//解锁
}
self.name = ;
为何没有崩溃呢?
从类型可以看出来,
内容多的name类型是__NSCFString
内容少的name类型是NSTaggedPointerString
这就是原因所在。
内容少的name,由于类型是NSTaggedPointerString,在赋值的时候
是直接在指针里面取值,而不需要release操作,因此,不会崩溃
https://www.cnblogs.com/r360/p/16524649.html
页:
[1]