本文主要研讨Tagged Pointer技能,针对该技能需求解决的问题、以及在实践应用中的价值做一些简单的讨论。

如果你想要更进一步,去挖掘Tagged Pointer是怎么完成的,能够参考Friday Q&A 2012-07-27: Let’s Build Tagged Pointers和objc源码。

别的,本文中涉及到的示例代码,请在真机iOS设备上测试,由于Tagged Pointer技能针对不同的平台,详细完成细节是有差异的,不然无法得出和本文共同的测试成果。

一、目标的内存

下面咱们针对iOS中目标进行一些探求,代码如下,其完好代码见TaggedPointer。


    __weak NSNumber *weakNumber;
    __weak NSString *weakString;
    __weak NSDate *weakDate;
    __weak NSObject *weakObj;
    int num = 123;
    @autoreleasepool {
        weakObj = [[NSObject alloc] init];
        weakNumber = [NSNumber numberWithInt:num];
        weakString = [NSString stringWithFormat:@"string%d", num];
        weakDate   = [NSDate dateWithTimeIntervalSince1970:0];
    }
    NSLog(@"weakObj is %@", weakObj);
    NSLog(@"weakNumber is %@", weakNumber);
    NSLog(@"weakString is %@", weakString);
    NSLog(@"weakDate is %@", weakDate);

第7行,首要界说了4个__weak***目标,构建了一个autoreleasepool,所以在12行之后,一切__weak润饰的弱引证目标,都会被释放。经过上面分析,咱们得出,目标会打印出null

但是,实践上,咱们得到了如下的输出。

TaggedPointer[3570:3928309] weakObj is (null)

TaggedPointer[3570:3928309] weakNumber is 123

TaggedPointer[3570:3928309] weakString is string123

TaggedPointer[3570:3928309] weakDate is Thu Jan 1 08:00:00 1970

能够看到,只要NSObject对应的目标值是null,其他的值,均正常打印。

这是由于NSNumberNSStringNSDate,在这里采用了Tagged Pointer技能。

二、Tagged Pointer

2.1 Tagged Pointer技能

2.1.1 简介

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

2.2.2 未引进Tagged Pointer

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

2.2.3 引进Tagged Pointer

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

2.2.4 判别是否是Tagged Pointer

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

2.2 应用

2.2.1 支持的目标类型

能够从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, 
    ....
};

即针对NSStringNSNumberNSDateNSIndexPath这些类型,都支持Tagged Pointer技能。

2.2.2 NSNumber

咱们经过NSNumber以及NSString目标来观察Tag+Data存储形式。

示例代码参见:TaggedPointer

如下所示,咱们创立了许多NSNumber目标:

    NSNumber *number1 = @1;                          //0xb000000000000012
    NSNumber *number2 = @2;                          //0xb000000000000022
    NSNumber *number3 = @(0xFFFFFFFFFFFFFFF);        //0x1c0022560
    NSNumber *number4 = @(1.2);                      //0x1c0024b80
    int num4 = 5;
    NSNumber *number5 = @(num4);                     //0xb000000000000052
    long num5 = 6;
    NSNumber *number6 = @(num5);                     //0xb000000000000063
    float num6 = 7;
    NSNumber *number7 = @(num6);                     //0xb000000000000074
    double num7 = 8;
    NSNumber *number8 = @(num7);                     //0xb000000000000085
    //值:0xb000000000000012 0xb000000000000022 0x1c0022560 0x1c0024b80 0xb000000000000052 0xb000000000000063 0xb000000000000074 0xb000000000000085
    NSLog(@"%p %p %p %p %p %p %p %p", number1, number2, number3, number4, number5, number6, number7, number8);

由上表咱们得出:

  • 很大的数字,超过Tagged Pointer表明上限的时分,将会转为目标存储,存放在堆上;
  • 如果是含有小数点的浮点数,将会直接以目标方法存储;
  • 其余类型的数字,包括不含小数部分的浮点型和整型都会以Tagged Pointer存储。

而且,针对以上部分,咱们整理出Tagged Pointer的存储格局如下,以number1为例:

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

2.2.3 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等创立的字符串目标。

以上,整理如下:

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

NSString以Tagged Pointer的存储格局如下:

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

2.3 内存办理

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

三、一个面试问题的研讨

该面试题如下:

iOS之”Tagged-Pointer“内存管理策略,设计的巧而小之美

参考

链接

1Friday Q&A 2012-07-27: Let’s Build Tagged Pointers 2Tagged Pointer wiki 3NSString retain count -1 4objc源码

示例代码

1TaggedPointer

青山不改,绿水常流!谢谢大家。