Tagged Pointer 介绍
苹果对于Tagged Pointer特点的介绍:
Tagged Pointer主要解决内存浪费和访问效率的问题
-
Tagged Pointer
专门用来存储小的对象,NSString
、NSNumber
、NSDate
、NSIndexPath
-
Tagged Pointer
指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc和free。 - 在内存读取上有着3倍的效率,创建时比以前快106倍 销毁速度更快
如果想深入了解
如果你想要更进一步,去挖掘 Tagged Pointer 是如何实现的,可以参考 Friday Q&A 2012-07-27: Let’s Build Tagged Pointers 和 objc 源码。
为什么要引入Tagged Pointer
iPhone5s 采用64位处理器。
对于64位程序,我们的数据类型的长度是跟CPU的长度有关的。
这样就导致了 一些对象占用的内存会翻倍。
同时 维护程序中的对象需要 分配内存,维护引用计数,管理生命周期,使用对象给程序的运行增加了负担。
Tagged Pointer
未引入 Tagged Pointer
image.png引入 Tagged Pointer
image.png判断是否是 Tagged Pointer
image.png
可以从 objc 源码中找出支持 Tagged Pointer 的对象类型,如下:
typedef uint16_t objc_tag_index_t;
enum
{
OBJC_TAG_NSString = 2,
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSDate = 6,
....
};
即针对 NSString、NSNumber、NSDate、NSIndexPath 这些类型,都支持 Tagged Pointer 技术。
我们通过 NSNumber 以及 NSString 对象来观察 Tag+Data 的存储形式
NSNumber *number1 = @1; //0xa061a1f0f2864c7a
NSNumber *number2 = @2; //0xa061a1f0f2864c4a
NSNumber *number3 = @(0xFFFFFFFFFFFFFFF); //0x600003eac120
NSNumber *number4 = @(1.2); //0x600003eac1c0
int num4 = 5;
NSNumber *number5 = @(num4); //0xa061a1f0f2864c3a
long num5 = 6;
NSNumber *number6 = @(num5); //0xa061a1f0f2864c0b
float num6 = 7;
NSNumber *number7 = @(num6); //0xa061a1f0f2864c1c
double num7 = 8;
NSNumber *number8 = @(num7); //0xa061a1f0f2864ced
//值: 0xa061a1f0f2864c7a 0xa061a1f0f2864c4a 0x600003eac120 0x600003eac1c0 0xa061a1f0f2864c3a 0xa061a1f0f2864c0b 0xa061a1f0f2864c1c 0xa061a1f0f2864ced
NSLog(@"%p %p %p %p %p %p %p %p", number1, number2, number3, number4, number5, number6, number7, number8);
由上表我们得出:
- 很大的数字,超过 Tagged Pointer 表示上限的时候,将会转为对象存储,存放在堆上;
- 如果是含有小数点的浮点数,将会直接以对象方式存储;
-
其余类型的数字,包括不含小数部分的浮点型和整型都会以 Tagged Pointer 存储。
并且,针对以上部分,我们整理出 Tagged Pointer 的存储格式如下,以 number1 为
image.png
NSString
同上面 NSNumber
的处理逻辑,NSString
处理的类似。
NSString *str1 = @"a"; //0x1049cc248
NSString *str2 = [NSString stringWithFormat:@"a"]; //0xa000000000000611
NSString *str3 = [NSString stringWithFormat:@"bccd"]; //0xa000000646363624
NSString *str4 = [NSString stringWithFormat:@"c"]; //0xa000000000000631
NSString *str5 = [NSString stringWithFormat:@"cdasjkfsdljfiwejdsjdlajfl"];//0x1c02418f0
NSLog(@"%@ %@ %@ %@ %@",
[str1 class], //__NSCFConstantString
[str2 class], //NSTaggedPointerString
[str3 class], //NSTaggedPointerString
[str4 class], //NSTaggedPointerString
[str5 class]); // __NSCFString
根据以上结果,我们将 NSString 分类三类:
- 常量类型:__NSCFConstantString,定义的字符串常量。
- Tagged Pointer 类型:NSTaggedPointerString,通过对象方法创建的短字符串。
- NSString 对象类型:__NSCFString,包括 NSString、NSMutableString 等创建的字符串对象。
以上,整理如下:
image-20190103150923946NSString 以 Tagged Pointer 的存储格式如下:
image-201901031516457482.3 内存管理
image-20190103151136639三、一个面试问题的研究
该面试题如下:
image-20190103151957866
网友评论