Tagged Pointer

作者: 和风细羽 | 来源:发表于2019-12-03 14:52 被阅读0次
NSNumber * number = [[NSNumber alloc] initWithInt:11];

普通对象要在堆区开辟 16 个字节来存储 ‘11’ 这个值,在栈区 8 个字节保存堆区地址,一个简单的 int 数值,原本最多只需要 4 个字节,结果至少占了 24 个字节,并且还有维护对象引用计数,释放内存等开销。

Tagged Pointer 技术将指针的值(8个字节)进行拆分,一部分表示数据,一部分用来表示这是一个特殊的指针。

  • 指针 = Data + Tag;
  • 1 位标识是否是 Tagged Pointer 指针;
  • 3 位标识数据类型;
  • 4 位标识数据(如字符串)的长度;
  • 有效存储位置有 56 位。

TaggedPointer 极大的提高了内存利用率和简化了查询步骤。它不单单是一个指针,还包括了其值+类型,节省了对象的查询流程。

查看真实的地址

extern uintptr_t objc_debug_taggedpointer_obfuscator;

@implementation TestTaggedPointer

/**
  *  @brief   与系统的解码方法只是名称不同,内容一致
  *  @see   objc-internal.h   _objc_decodeTaggedPointeraa() 方法
  */
uintptr_t _objc_decodeTaggedPointer_(const void * _Nullable  ptr) {
    return (uintptr_t)ptr ^ objc_debug_taggedpointer_obfuscator;
}


+ (void)test
{    
    int     num1 = 15;
    float   num2 = 11;
    double  num3 = 10;
    long    num4 = 8;
    
    NSNumber * number1 = @(num1);
    NSNumber * number2 = @(num2);
    NSNumber * number3 = @(num3);
    NSNumber * number4 = @(num4);
    
    NSLog(@"number1 = %@ - %p - 0x%lx", object_getClass(number1), &number1, _objc_decodeTaggedPointer_((__bridge const void * _Nullable)(number1)));
    NSLog(@"number2 = %@ - %p - 0x%lx", object_getClass(number2), &number2, _objc_decodeTaggedPointer_((__bridge const void * _Nullable)(number2)));
    NSLog(@"number3 = %@ - %p - 0x%lx", object_getClass(number3), &number3, _objc_decodeTaggedPointer_((__bridge const void * _Nullable)(number3)));
    NSLog(@"number4 = %@ - %p - 0x%lx", object_getClass(number4), &number4, _objc_decodeTaggedPointer_((__bridge const void * _Nullable)(number4)));

    // number1 = __NSCFNumber - 0x7ffeefbff598 - 0xf27
    // number2 = __NSCFNumber - 0x7ffeefbff590 - 0xb47
    // number3 = __NSCFNumber - 0x7ffeefbff588 - 0xa57
    // number4 = __NSCFNumber - 0x7ffeefbff580 - 0x837
    
    NSNumber * number5 = [[NSNumber alloc] initWithInt:9];
    NSLog(@"number5 = %@ - %p - 0x%lx", object_getClass(number5), &number5, _objc_decodeTaggedPointer_((__bridge const void * _Nullable)(number5)));

    // number5 = __NSCFNumber - 0x7ffeefbff578 - 0x927
    
    //0xf27、0xb47、0xa57 这些是真实的地址
}

@end

从上面的真实地址可以做一些猜测:

  • number1(0xf27) 和 number5(0x927) 末尾都是 27,有差别的地方是 f9,因 f = 15,所以猜测 Tagged Pinter 从第 9 位开始存储数值。
  • number1(0xf27)、number2(0xb47)、number3(0xa57)等,低 8 位的值各不同,结合它们的数据类型,可猜测 27、47、57 是在标记它们的数据类型。

以上只是简单的、杂乱的记录些知识点,详细的查看下面的链接

详细文章

kwdx - TaggedPointer
fanglaoda - 你不知道的TaggedPointer

相关文章

网友评论

    本文标题:Tagged Pointer

    本文链接:https://www.haomeiwen.com/subject/skycgctx.html