Tagged Pointer

  • 从64bit开始,iOS引入了Tagged Pointer技术,用于优化NSNumber、NSDate、NSString等小对象的存储
  • 在没有使用Tagged Pointer之前, NSNumber等对象需要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值
  • 使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了:Tag + Data,也就是将数据直接存储在了指针中
  • 当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
  • objc_msgSend能识别Tagged Pointer,其内部会判断该对象是不是Tagged Pointer,如果是就不会调用消息发送,而是直接从地址中将值取出来,比如NSNumber的intValue方法,直接从指针提取数据,节省了以前的调用开销
  • 如何判断一个指针是否为Tagged Pointer?
  • iOS平台,最高有效位是1(第64bit)
  • Mac平台,最低有效位是1
  • 对象的内存地址最后一位都是 0,因为内存对齐,所以地址值都是 16 的倍数

问题

下面两段代码有什么区别

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    for (int i = 0; i < 1000; i++) {
        dispatch_async(queue, ^{
            self.name = [NSString stringWithFormat:@"abcdefghi hjijoijoijk"];
        });
    }
    dispatch_queue_t queue1 = dispatch_get_global_queue(0, 0);
    for (int i = 0; i < 1000; i++) {
        dispatch_async(queue1, ^{
            self.name = [NSString stringWithFormat:@"abc"];
        });
    }
  • 第一段代码会崩溃,第二段不会
    第一段代码在给name 赋值的时候有可能会多线程访问 name 的 set 方法,而setName方法的实现会是下面的样子,这样有可能_name 被一个线程 release 后,又被另外一个线程 release.这样就会造成怀内存访问。而第二段不会,由于第二段的字符串比较短,会采用 tagged Pointer 技术,将其内容放在指针里,不会申请堆控件,也就不会有对象的retain 和 release,这样就不会有因多次 release 造成的坏内存访问。
- (void)setName:(NSString *)name{
    if (_name != name) {
        [_name release];
        _name = [name retain];
    }
}

你可能感兴趣的:(Tagged Pointer)