-
Tagged Pointer
从 5s 开始,iPhone 均使用 arm64 指令集的处理器。在 64 位系统上,一个指针占 8 个字节,而指针指向的实例变量至少需要 16 个字节,并且还需要执行额外的一些操作,例如:申请内存,销毁内存。为了达到优化的目的,苹果将一些存储数据的类,例如 NSString,NSNumber,当它们需要保存的数据不需要占用那么多的字节时,直接将数据保存在“指针”里面。
enum
#endif
{
// 60-bit payloads
OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2,
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6,
// 60-bit reserved
OBJC_TAG_RESERVED_7 = 7,
// 52-bit payloads
OBJC_TAG_Photos_1 = 8,
OBJC_TAG_Photos_2 = 9,
OBJC_TAG_Photos_3 = 10,
OBJC_TAG_Photos_4 = 11,
OBJC_TAG_XPC_1 = 12,
OBJC_TAG_XPC_2 = 13,
OBJC_TAG_XPC_3 = 14,
OBJC_TAG_XPC_4 = 15,
OBJC_TAG_NSColor = 16,
OBJC_TAG_UIColor = 17,
OBJC_TAG_CGColor = 18,
OBJC_TAG_NSIndexSet = 19,
OBJC_TAG_First60BitPayload = 0,
OBJC_TAG_Last60BitPayload = 6,
OBJC_TAG_First52BitPayload = 8,
OBJC_TAG_Last52BitPayload = 263,
OBJC_TAG_RESERVED_264 = 264
};
NSString *str = [NSString stringWithFormat:@"%@",@"fffff"];
NSNumber *a1 = [NSNumber numberWithInt:2];
NSLog(@"str - %lx",((uintptr_t)str ^ objc_debug_taggedpointer_obfuscator));
NSLog(@"a - %lx",((uintptr_t)a ^ objc_debug_taggedpointer_obfuscator));
打印结果:
str - 'a000066666666665'
a - 'b000000000000022'
str
指针中a
转成二进制为1010
,最高位的1
标识tagged pointer
;010
为2
,由上面的枚举值可知是OBJC_TAG_NSString
,标识字符串;最低位5
则标识字符串个数(number类型最低位标识值类型,2、4、5、3
分别代表int long float double
),中间位则用来存储数值
Tagged Pointer
的引用主要解决内存浪费和访问效率的问题。所以其有以下特点:
1、Tagged Pointer
专门用于存储小的对象,例如:NSString
、NSNumber
和NSDate
。
2、Tagged Pointer
指针的值不再是堆区地址,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc
和free
。
3、在内存读取上有着3 倍
的效率,创建时比以前快106 倍
由此可见,苹果引入Tagged Pointer,不但减少了 64 位机器下程序的内存占用,还提高了运行效率。完美地解决了小内存对象在存储和访问效率上的问题。
-
引用计数
黄金法则
- 自己生成的对象,自己持有
- 非自己生成的对象,自己也能持有
- 不在需要自己持有对象的时候,释放
- 非自己持有的对象无需释放
拓展
- 野指针、僵尸对象、空指针
当一个指针变量p指向一个对象obj的地址空间,则称p持有obj,obj的引用计数+1,当obj引用计数为0被释放,则p不再持有obj,如果obj不被销毁,则p就叫做野指针,obj叫做僵尸对象,如果将obj销毁,则p不指向任何内存地址,p叫做空指针