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,有差别的地方是
f
和9
,因 f = 15,所以猜测 Tagged Pinter 从第 9 位开始存储数值。 - number1(0xf27)、number2(0xb47)、number3(0xa57)等,低 8 位的值各不同,结合它们的数据类型,可猜测 27、47、57 是在标记它们的数据类型。
以上只是简单的、杂乱的记录些知识点,详细的查看下面的链接。
网友评论