iOS內存管理之Tagged Pointer

什么是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"];
        });
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容