iOS Tagged Pointer

先看两段代码:
第一段:

@property (nonatomic, strong) NSString *name;
- (void)test1 {
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 1000; i++) {
        dispatch_async(queue, ^{
            self.name = [NSString stringWithFormat:@"abcde"];
        });
    }
}

第二段:

@property (nonatomic, strong) NSString *name;
- (void)test2 {
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 1000; i++) {
        dispatch_async(queue, ^{
            self.name = [NSString stringWithFormat:@"abcdefghjsfdasdfas"];
        });
    }
}

结论:
第一段代码运行没什么问题;第二段代码运行崩溃,报EXC_BAD_ACCESS,坏内存。

分析:
由于不管是否是在ARC环境下,还是在MRC环境下,底层都是转化成MRC进行编译的。所以对self.name进行赋值相当于下面代码:

- (void)setName:(NSString *)name {
    if (_name != name) {
        id pre = _name;
        
        // 1.先保留新值
        [name retain];
        
        // 2.再进行赋值
        _name = name;
        
        // 3.释放旧值
        [pre release];
    }
}

因为释放旧值是在多条线程同步进行的,所以就会出现当前内存已经被释放了的情况下,接着又被重新释放一次,所以就会导致坏内存的情况出现;但为啥第一段代码不会出错呢?

我们接下来看下两段字符串的对象类型及内存地址:


iOS Tagged Pointer_第1张图片
对比.png

通过控制台打印的日志,可以看出有一个是TaggedPointer的类型。
接下来可以参考深入理解 Tagged Pointer这篇博客

Tagged Pointer 是一个能够提升性能、节省内存的有趣的技术。

  • Tagged Pointer 专门用来存储小的对象,例如 NSNumber 和 NSDate(后来可以存储小字符串)
  • Tagged Pointer 指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。
  • 它的内存并不存储在堆中,也不需要 malloc 和 free,所以拥有极快的读取和创建速度。

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