思考一下2段代码能发生什么事?有什么区别
- 全局并发队列循环1000次异步任务设置name,1000次可能会同时对self.name 进行设置。
- 结果是第一段代码报错,第二段没有问题。
- 这两段代码唯一的差别就是字符串的长度不一样,为什么会这样呢?
- 这个NSTaggedPointer到底是什么呢
- 首先查看set方法在MRC下的操作本质是
@property (strong, nonatomic) NSString *name;
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];
_name = [name retain];
}
}
@property (copy, nonatomic) NSString *name;
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];
_name = [name copy];
}
}
- 1.判断是否一致
- 2.引用计数减一,释放旧的成员变量
- 3.赋值引用计数+1。
- 所以这里线程可能会多次调用release。导致坏内存访问。
- 处理方案1 改成atomic
- 处理方案2 加锁解锁 。
Tagged Pointer
-
从64bit开始,iOS引入了Tagged Pointer技术,用于优化NSNumber、NSDate、NSString等小对象的存储
-
在没有使用Tagged Pointer之前, NSNumber等对象需要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值
-
使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了:Tag + Data,也就是将数据直接存储在了指针中
-
当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
-
objc_msgSend能识别Tagged Pointer,比如NSNumber的intValue方法,直接从指针提取数据,节省了以前的调用开销
-
如何判断一个指针是否为Tagged Pointer?
- iOS平台,最高有效位是1(第64bit)
- Mac平台,最低有效位是1
-
当字符串字数较少时使用的时TaggedPointer,将数据直接放到了指针当中。
-
比如这个NSNumber就存放到指针中了。
-
再来验证NSNumber
-
@4 = 0x427 4是真实数据 27是tag标志,说明数据是 NSNumber类型 在mac平台型 是7 = 0b0111 最低有效位是1所以判断是taggedPointer 类型。
-
ios 是最高位 如上面的例子
- b = 0b1011 最高有效位是1 所以判断是 taggedPointer类型