美文网首页
iOS 中的Tagged Pointer

iOS 中的Tagged Pointer

作者: 希尔罗斯沃德_董 | 来源:发表于2021-08-26 20:24 被阅读0次

    什么是Tagged Pointer对象

    Tagged Pointer对象一般用于NSNumber、NSDate、NSString等小对象的存储。通常来说,普通对象对象需要动态分配内存、维护引用计数等,对象指针存储的是堆中的对象的地址值。而Tagged Pointer对象呢,其指针里面不是地址,而是它的值。所以Tagged Pointer实际上已经不能算是对象了,只是一个对象皮的普通变量。它的内存并不存在堆中,也不需要malloc和free。Tagged Pointer对象不仅节省内存,在内存读取和对象创建上效率大大提高。

    什么样的对象算小对象?所有的NSNumber、NSDate、NSString都是小对象吗?

    小对象往往指的是占内存较小的对象,小道什么程度呢?小到它的值可以存储在对象的指针里面。在iOS中对象的指针是8位,8*8=64bit,由于对象指针本身还要存储地址,对很多占用内存比较小的对象,比如NSNumber、NSDate、NSString,它们有时候内存很小,可以直接和地址存储在对象指针里面,不需要开辟堆空间来存储。但是当它们的内存比较大时,指针存不下时,也会开辟堆空间来存储。下面我们以字符串为例子来演示一下:
    首先创建一个字符串属性,用strong修饰:

    @property (nonatomic, strong) NSString *aString;
    

    接着多线程给aString进行赋值操作,如demo1:

     dispatch_queue_t queue = dispatch_queue_create("com.djx.cn", DISPATCH_QUEUE_CONCURRENT);
        
        for (int i = 0; i<10000; i++) {
            dispatch_async(queue, ^{
                self.aString = [NSString stringWithFormat:@"123456789"];  
                 NSLog(@"%@",self.aString);
            });
        }
    

    这段代码运行时正常的。但是如果我们把字符串长度在增加一下,如demo2:

    dispatch_queue_t queue = dispatch_queue_create("com.djx.cn", DISPATCH_QUEUE_CONCURRENT);
        
        for (int i = 0; i<10000; i++) {
            dispatch_async(queue, ^{
                self.aString = [NSString stringWithFormat:@"1234567890"];  
                 NSLog(@"%@",self.aString);
            });
        }
    

    这段代码就会崩溃,为什么?这里demo2和demo1的不同仅仅是因为demo1的字符串长度为9位,而demo2字符串长度为10位,就多了以为,就会崩溃。补充:字符串的在内存中比较特殊,字符串主要有三种存储形式:

    1、Tagged Pointer对象,就像上面介绍的那样;
    2、存储在常量区,比如aString = @"ureryueyr"等,这种在编译期就能确定的就存在常量区,不存在引用计数管理的问题;
    3、普通的字符串对象,通过stringWithFormat创建较长的字符串,比如上面的demo2,此时跟其他OC对象没有区别。

    分析:首先因为属性aString是用strong修饰的,demo2崩溃的原因是因为set方法里进行了retain和release操作,在release操作的时候,由于多线程的原因,有可能变量刚release,又被其他线程release导致过度释放的问题。但是demo1为什么就不会崩溃的?原因在于demo1中的对象是个Tagged Pointer对象。怎么知道?
    demo1运行时:

    tagged_point.jpeg
    demo2运行时:
    普通对象.jpeg
    对比demo1和demo2发现,demo1的对象是Tagged Pointer对象,demo2是普通的对象。为什么Tagged Pointer对象多线程set就不会崩溃呢?

    Tagged Pointer对象的内存管理

    它们内存管理是没有通过引用计数来管理,自然就会出现像普通对象的过度释放的崩溃信息:

    __attribute__((aligned(16), flatten, noinline))
    id 
    objc_retain(id obj)
    {
        if (obj->isTaggedPointerOrNil()) return obj;
        return obj->retain();
    }
    
    __attribute__((aligned(16), flatten, noinline))
    void 
    objc_release(id obj)
    {
        if (obj->isTaggedPointerOrNil()) return;
        return obj->release();
    }
    
    __attribute__((aligned(16), flatten, noinline))
    id
    objc_autorelease(id obj)
    {
        if (obj->isTaggedPointerOrNil()) return obj;
        return obj->autorelease();
    }
    

    通过源码可以看到,如果是Tagged Pointer对象,就不会进行retain和release操作。

    相关文章

      网友评论

          本文标题:iOS 中的Tagged Pointer

          本文链接:https://www.haomeiwen.com/subject/jzluiltx.html