Tagged Pointer

NSNumber

因为在从32位升级到64位后,同一个对象占用的内存会变成原来的2倍,为了节省内存和访问效率而引入了TaggedPointer. 像NSNumber,NSDate的地址不是真正的地址,如果是NSNumber@(1),@(2),那么地址分别是是

(__NSCFNumber *) $0 = 0xb000000000000012 (int)1
(__NSCFNumber *) $3 = 0xb000000000000022 (int)2

我们发现倒数第2位就是存储的真实值,它会以0xb......2这样的格式展示,指针包含两部分,一部分是真实值,一部分是特殊标记。但是这样的话,如果数值过大,位数就不够了。我们测试一下,我们用一个特别大的值,@(0xEFFFFFFFFFFFFFFF),地址是:

(__NSCFNumber *) $5 = 0x00006000000320e0 

结果很像一个指针,这个是真正的指针,它没有用到TaggedPointer。

ISA失效

虽然taggedPointer有一定的好处,但是它并不是一真正的对象,而是个伪对象,所以我们不能直接获取它的isa,否则就会报错。为了获取Isa,我们定义一个假的tempObject结构体来抽取isa指针:

    struct tempObject {
        Class isa;
    };
    ViewController *vc = [[ViewController alloc] init];
    struct tempObject *oo = (__bridge struct tempObject *)number;
    Class isa = oo->isa;

结果运行时报错,访问了野指针:

Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

说明它根本就没有isa指针。但是如果我们用object_getClass()[NSNumber Class]来获取isa时会返正确的的Class:__NSCFNumber。因为苹果已经伪装好了,很多runtime API里都会判断是否是TaggedPointer对象,会对它单独进行处理。

你可能感兴趣的:(Tagged Pointer)