小对象存储标记指针 Tagged Pointer

在2013年9月,苹果推出了iPhone5s,配备了首个采用64位架构的A7双核处理器,为了节省内存和提高执行效率,苹果提出了标记指针(Tagged Pointer)
的概念。对于64位程序,引入Tagged Pointer后,相关逻辑能减少一半的内存占用,以及3倍的访问速度提升,100倍的创建、销毁速度提升。

原有的对象为什么会浪费内存?

假设我们要存储一个NSNumber对象,其值是一个整数。正常情况下,如果这个整数只是一个NSInteger的普通变量,那么它所占用的内存是与CPU的位数有关,在32位CPU下占4个字节,在64位CPU下是占8个字节的。而指针类型的大小通常也是与CPU位数相关,一个指针所占用的内存在32位CPU下为4个字节,在64位CPU下也是8个字节。

所以一个普通的iOS程序,如果没有Tagged Pointer对象,从32位机器迁移到64位机器中后,虽然逻辑没有任何变化,但这种NSNumber、NSDate一类的对象所占用的内存会翻倍。

对象为什么会浪费内存

效率上的问题,为了存储和访问一个NSNumber对象,需要在堆上为其分配内存,另外还要维护它的引用计数,管理它的生命期。这些都给程序增加了额外的逻辑,造成运行效率上的损失。

Tagged Pointer

为了改进上面提到的内存占用和效率问题,苹果提出了Tagged Pointer对象。由于NSNumber、NSDate一类的变量本身的值需要占用的内存大小常常不需要8个字节,拿整数来说,4个字节所能表示的有符号整数就可以达到20多亿(注:2^31=2147483648,另外1位作为符号位),对于绝大多数情况都是可以处理的。

 

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

Tagged Pointer 专门用来存储小的对象,例如 NSNumber 和 NSDate、NSString

Tagged Pointer 指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。

它的内存并不存储在堆中,也不需要 malloc 和 free,所以拥有极快的读取和创建速度。

    NSString *str1 = [NSString stringWithFormat:@"abcdefghijk"];
    NSString *str2 = [NSString stringWithFormat:@"abcdefghi"];

    NSLog(@"%@ %p", [str1 class], str1);
    NSLog(@"%zd", malloc_size((__bridge const void *)(str1)));
    NSLog(@"%@ %p", [str2 class], str2);
    NSLog(@"%zd", malloc_size((__bridge const void *)(str2)));

打印

2021-05-20 09:24:37.581207+0800 TaggedPointerTest[76441:3083677] __NSCFString 0x600001efd5c0
2021-05-20 09:24:37.581342+0800 TaggedPointerTest[76441:3083677] 32
2021-05-20 09:24:37.581460+0800 TaggedPointerTest[76441:3083677] NSTaggedPointerString 0xe93a3e833fb1984b
2021-05-20 09:24:37.581535+0800 TaggedPointerTest[76441:3083677] 0
在北京的灯中,有一盏是我家的。这个梦何时可以实现?哪怕微微亮。北京就像魔鬼训练营,有能力的留,没能力的走……
原文地址:https://www.cnblogs.com/huangzs/p/14788526.html