本文主要研究Tagged Pointer技術,針對該技術需要解決的問題、以及在實際應用中的價值做一些簡單的探討,
如果你想要更進一步,去挖掘Tagged Pointer是如何實作的,可以參考Friday Q&A 2012-07-27: Let's Build Tagged Pointers和objc原始碼,
另外,本文中涉及到的示例代碼,請在真機iOS設備上測驗,因為Tagged Pointer技術針對不同的平臺,具體實作細節是有差異的,否則無法得出和本文一致的測驗結果,
一、物件的記憶體
下面我們針對iOS中物件進行一些探究,代碼如下,其完整代碼見TaggedPointer,
__weak NSNumber *weakNumber;
__weak NSString *weakString;
__weak NSDate *weakDate;
__weak NSObject *weakObj;
int num = 123;
@autoreleasepool {
weakObj = [[NSObject alloc] init];
weakNumber = [NSNumber numberWithInt:num];
weakString = [NSString stringWithFormat:@"string%d", num];
weakDate = [NSDate dateWithTimeIntervalSince1970:0];
}
NSLog(@"weakObj is %@", weakObj);
NSLog(@"weakNumber is %@", weakNumber);
NSLog(@"weakString is %@", weakString);
NSLog(@"weakDate is %@", weakDate);
在第7行,首先定義了4個__weak***物件,構建了一個autoreleasepool,所以在12行之后,所有__weak修飾的弱參考物件,都會被釋放,經過上面分析,我們得出,物件會列印出null,
但是,實際上,我們得到了如下的輸出,
TaggedPointer[3570:3928309] weakObj is (null)
TaggedPointer[3570:3928309] weakNumber is 123
TaggedPointer[3570:3928309] weakString is string123
TaggedPointer[3570:3928309] weakDate is Thu Jan 1 08:00:00 1970
可以看到,只有NSObject對應的物件值是null,其他的值,均正常列印,
這是因為NSNumber、NSString、NSDate,在這里采用了Tagged Pointer技術,
二、Tagged Pointer
2.1 Tagged Pointer技術
2.1.1 簡介
2.2.2 未引入Tagged Pointer
2.2.3 引入Tagged Pointer
2.2.4 判斷是否是Tagged Pointer
2.2 應用
2.2.1 支持的物件型別
可以從objc原始碼中找出支持Tagged Pointer 的物件型別,如下:
typedef uint16_t objc_tag_index_t;
enum
{
OBJC_TAG_NSString = 2,
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSDate = 6,
....
};
即針對NSString、NSNumber、NSDate、NSIndexPath這些型別,都支持Tagged Pointer技術,
2.2.2 NSNumber
我們通過NSNumber以及NSString物件來觀察Tag+Data的存盤形式,
示例代碼參見:TaggedPointer
如下所示,我們創建了很多NSNumber物件:
NSNumber *number1 = @1; //0xb000000000000012
NSNumber *number2 = @2; //0xb000000000000022
NSNumber *number3 = @(0xFFFFFFFFFFFFFFF); //0x1c0022560
NSNumber *number4 = @(1.2); //0x1c0024b80
int num4 = 5;
NSNumber *number5 = @(num4); //0xb000000000000052
long num5 = 6;
NSNumber *number6 = @(num5); //0xb000000000000063
float num6 = 7;
NSNumber *number7 = @(num6); //0xb000000000000074
double num7 = 8;
NSNumber *number8 = @(num7); //0xb000000000000085
//值:0xb000000000000012 0xb000000000000022 0x1c0022560 0x1c0024b80 0xb000000000000052 0xb000000000000063 0xb000000000000074 0xb000000000000085
NSLog(@"%p %p %p %p %p %p %p %p", number1, number2, number3, number4, number5, number6, number7, number8);
由上表我們得出:
- 很大的數字,超過Tagged Pointer表示上限的時候,將會轉為物件存盤,存放在堆上;
- 如果是含有小數點的浮點數,將會直接以物件方式存盤;
- 其余型別的數字,包括不含小數部分的浮點型和整型都會以Tagged Pointer存盤,
并且,針對以上部分,我們整理出Tagged Pointer的存盤格式如下,以number1為例:
2.2.3 NSString
同上面NSNumber的處理邏輯,NSString處理的類似,
NSString *str1 = @"a"; //0x1049cc248
NSString *str2 = [NSString stringWithFormat:@"a"]; //0xa000000000000611
NSString *str3 = [NSString stringWithFormat:@"bccd"]; //0xa000000646363624
NSString *str4 = [NSString stringWithFormat:@"c"]; //0xa000000000000631
NSString *str5 = [NSString stringWithFormat:@"cdasjkfsdljfiwejdsjdlajfl"];//0x1c02418f0
NSLog(@"%@ %@ %@ %@ %@",
[str1 class], //__NSCFConstantString
[str2 class], //NSTaggedPointerString
[str3 class], //NSTaggedPointerString
[str4 class], //NSTaggedPointerString
[str5 class]); // __NSCFString
根據以上結果,我們將NSString分類三類:
- 常量型別:__NSCFConstantString,定義的字串常量,
- Tagged Pointer型別:NSTaggedPointerString,通過物件方法創建的短字串,
- NSString物件型別:__NSCFString,包括NSString、NSMutableString等創建的字串物件,
以上,整理如下:
NSString以Tagged Pointer的存盤格式如下:
2.3 記憶體管理
三、一個面試問題的研究
該面試題如下:
參考
鏈接
1Friday Q&A 2012-07-27: Let's Build Tagged Pointers
2Tagged Pointer wiki
3NSString retain count -1
4objc原始碼
示例代碼
1TaggedPointer
青山不改,綠水常流!謝謝大家支持,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/502418.html
標籤:iOS
