什么是Tagged Pointer
- 從64bit開始,iOS引入了Tagged Pointer技術,用于優化NSNumber、NSDate、NSString等小對象的存儲
- 在沒有使用Tagged Pointer之前, NSNumber等對象需要動態分配內存、維護引用計數等,NSNumber指針存儲的是堆中NSNumber對象的地址值
- 使用Tagged Pointer之后,NSNumber指針里面存儲的數據變成了:Tag + Data,也就是將數據直接存儲在了指針中
- 當指針不夠存儲數據時,才會使用動態分配內存的方式來存儲數據
- objc_msgSend能識別Tagged Pointer,比如NSNumber的intValue方法,直接從指針提取數據,節省了以前的調用開銷
- 如何判斷一個指針是否為Tagged Pointer?
iOS平臺,最高有效位是1(第64bit)
Mac平臺,最低有效位是1
代碼演示
從下面的代碼的打印里看出,@4 @5用了Tagged Pointer,而number3指向了內存地址
#import <Foundation/Foundation.h>
BOOL isTaggedPointer(id pointer)
{
return (long)(__bridge void *)pointer & 1;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSNumber *number1 = @4;
NSNumber *number2 = @5;
NSNumber *number3 = @(0xFFFFFFFFFFFFFFF);
number1.intValue;
NSLog(@"%d %d %d", isTaggedPointer(number1), isTaggedPointer(number2), isTaggedPointer(number3));
NSLog(@"%p %p %p", number1, number2, number3);
}
return 0;
}
// 打印結果
2019-09-30 22:20:09.313900+0800 Interview04-TaggedPointer[22134:2121727] 1 1 0
2019-09-30 22:20:09.314289+0800 Interview04-TaggedPointer[22134:2121727]
0xfee2cd9e4f48bf2d
0xfee2cd9e4f48be2d
0x100722ca0
代碼找錯
1.崩潰,原因是多線程訪問了self的set方法,沒加鎖的情況下會多次釋放產生崩潰
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"abcdefghijk"];
});
}
2.不訪問get方法,原因是Tagged Pointer技術會直接修改內存中的值。
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"abc"];
});
}