iOS--内存管理 Tagged Pointer

Tagged Pointer

从64位开始iOS引入了Tagged Pointer技术,用于优化NSNumber NSDate NSString等小对象的存储,节省内存空间

在没有引入该技术之前,NSNumber等对象要分配内存,维护引用计数等,NSNumber指针存储的是堆中的NSNumber对象的地址,需要一个栈和一个堆的空间 开销很大,但是我只是存储一个整形用不着这么多空间。

使用tagged pointer之后,NSNumber指针存书的数据就变成Tag+Data,也就是说是将数据直接存储在指针中。

当NSNumber 存储很大的数据,动态分配内存,存在堆中。
最低有效位为1,那就是TaggedPointer类型,最低有效位为0,那就是对象类型。

NSNumber *number = @4;

[number intValue] ; 

在objc_msgSend()中会判断是否是TaggedPoint 如果是那就直接从指针获取到对应的值。少耗性能

在使用taggedPointer的时候需要注意点

- (void)test1{

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    for(int i =0; i <1000;i++){

        dispatch_async(queue, ^{

            self.name = [NSString  stringWithFormat:@"abcasasfdssafa"];

        });

    }

}

iOS--内存管理 Tagged Pointer

  self.name = [NSString  stringWithFormat:@"abcasasfdssafa"];会调用一个setter方法,改写成MRC格式

- (void)setName:(NSString *)name{

    if(_name != name){

        [_name release];

        _name = [name retain];

    }

}

有多条线程同时进入setter方法,那么就会存在多次释放_name 的操作,坏内存访问。

将改成atomic,在 dispatch_async 增加锁

- (void)test2{

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    for(int i =0; i <1000;i++){

        dispatch_async(queue, ^{

            self.name = [NSString  stringWithFormat:@"abc"];

        });

    }

}

赋值abc 直接存在Tagged Pointer指针中,不用走对象set方法

NSString *str1 = [NSString  stringWithFormat:@"abcasasfdssafa"];

    NSLog(@" before self.name===%p", str1);    

    NSString *str2 = [NSString  stringWithFormat:@"abc"];

    NSLog(@" after self.name===%p",  str2);

before self.name===0x60000025e740        heap

 after self.name===0xcd26d822a5963603 tagged pointer

NSString *str1 = [NSString  stringWithFormat:@"abcasasfdssafa"];

    NSLog(@" before self.name===%@", [str1 class]);

    NSString *str2 = [NSString  stringWithFormat:@"abc"];

    NSLog(@" after self.name===%@",  [str2 class]);

before self.name===__NSCFString

2020-10-25 12:15:15.910546+0800 LearnLoadInitial[23497:1909251]  after self.name===NSTaggedPointerString

源码中objc-internal文件判断是否是Tagged Pointer 

_objc_isTaggedPointer(const void * _Nullable ptr)

{

    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;

}

iOS平台

#   define _OBJC_TAG_MASK (1UL<<63)

MACo平台

define _OBJC_TAG_MASK 1UL