ios的Tagged Pointer

781 阅读2分钟

思考一下2段代码能发生什么事?有什么区别 image.png image.png

  • 全局并发队列循环1000次异步任务设置name,1000次可能会同时对self.name 进行设置。
  • 结果是第一段代码报错,第二段没有问题。 image.png
  • 这两段代码唯一的差别就是字符串的长度不一样,为什么会这样呢? image.png
  • 这个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 image.png
  • 处理方案2 加锁解锁 。 image.png

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就存放到指针中了。 image.png

  • 再来验证NSNumber image.png

  • @4 = 0x427 4是真实数据 27是tag标志,说明数据是 NSNumber类型 在mac平台型 是7 = 0b0111 最低有效位是1所以判断是taggedPointer 类型。

  • ios 是最高位 如上面的例子

image.png

  • b = 0b1011 最高有效位是1 所以判断是 taggedPointer类型

image.png