内存管理之内存布局

  • 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 pointer0102,由上面的枚举值可知是OBJC_TAG_NSString,标识字符串;最低位5则标识字符串个数(number类型最低位标识值类型,2、4、5、3分别代表int long float double),中间位则用来存储数值

Tagged Pointer 的引用主要解决内存浪费和访问效率的问题。所以其有以下特点:
1、Tagged Pointer 专门用于存储小的对象,例如:NSStringNSNumberNSDate
2、Tagged Pointer指针的值不再是堆区地址,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要 mallocfree
3、在内存读取上有着 3 倍的效率,创建时比以前快 106 倍

由此可见,苹果引入Tagged Pointer,不但减少了 64 位机器下程序的内存占用,还提高了运行效率。完美地解决了小内存对象在存储和访问效率上的问题。

  • 引用计数

黄金法则

  • 自己生成的对象,自己持有
  • 非自己生成的对象,自己也能持有
  • 不在需要自己持有对象的时候,释放
  • 非自己持有的对象无需释放

拓展

  • 野指针、僵尸对象、空指针
当一个指针变量p指向一个对象obj的地址空间,则称p持有obj,obj的引用计数+1,当obj引用计数为0被释放,则p不再持有obj,如果obj不被销毁,则p就叫做野指针,obj叫做僵尸对象,如果将obj销毁,则p不指向任何内存地址,p叫做空指针

你可能感兴趣的:(内存管理之内存布局)