iOS Tagged Pointer (源碼閱讀必備知識)

Tagged Pointer 介紹

蘋果對於Tagged Pointer特色的介紹:c++

  1. Tagged Pointer專門用來存儲小的對象,例如NSNumber和NSDate
  2. Tagged Pointer指針的值再也不是地址了,而是真正的值。因此,實際上它再也不是一個對象了,它只是一個披着對象皮的普通變量而已。因此,它的內存並不存儲在堆中,也不須要malloc和free。
  3. 在內存讀取上有着3倍的效率,建立時比之前快106倍。

爲何要引入Tagged Pointer

iPhone5s 採用64位處理器。
對於64位程序,咱們的數據類型的長度是跟CPU的長度有關的。objective-c

這樣就致使了 一些對象佔用的內存會翻倍。測試

同時 維護程序中的對象須要 分配內存,維護引用計數,管理生命週期,使用對象給程序的運行增長了負擔。ui

Tagged Pointer

爲了改進上面提到的內存佔用和效率問題,蘋果提出了Tagged Pointer對象。因爲NSNumber、NSDate一類的變量自己的值須要佔用的內存大小經常不須要8個字節,拿整數來講,4個字節所能表示的有符號整數就能夠達到20多億(注:2^31=2147483648,另外1位做爲符號位),對於絕大多數狀況都是能夠處理的。this

咱們能夠將一個對象的指針拆成兩部分,一部分直接保存數據,另外一部分做爲特殊標記,表示這是一個特別的指針,不指向任何一個地址。因此,引入了Tagged Pointer對象以後,64位CPU下NSNumber的內存圖變成了如下這樣:
Tagged Pointerspa

測試

#import 
  
  
  

 
  
  int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSNumber *number1 = @1; NSNumber *number2 = @2; NSNumber *number3 = @3; NSNumber *numberFFFF = @(0xFFFF); NSNumber *numberLager = @(MAXFLOAT); NSLog(@"number1 pointer is %p", number1); NSLog(@"number2 pointer is %p", number2); NSLog(@"number3 pointer is %p", number3); NSLog(@"numberLager pointer is %p", numberLager); /* 2017-03-10 12:07:50.731726 TaggedPoint[1690:50438] number1 pointer is 0x127 2017-03-10 12:07:50.731992 TaggedPoint[1690:50438] number2 pointer is 0x227 2017-03-10 12:07:50.732011 TaggedPoint[1690:50438] number3 pointer is 0x327 2017-03-10 12:07:50.732043 TaggedPoint[1690:50438] numberLager pointer is 0x1002006a0 */ } return 0; } 

 複製代碼

以 0x127 爲例 去掉 tag27(假設27爲標記) 0x1 就是number 的值。
0x227
0x327
都有這種規律指針

numberLager 存儲的值爲MAXFloat 顯然超過了tagged pointer 能夠存儲的範圍。
因此打印的地址是單純的指針地址,指向存儲numberLager的內存地址。code

對於isa指針的影響

由於tagged pointer 不是一個真正的對象,若是使用isa指針在編譯時會報錯。
如圖:cdn


提示咱們改成object_getClass()
object_getClass()中作了相應的處理

因爲object_getClass()沒有對應的實現,只能從其餘地方窺探一二
objc-weak.mm對象

weak_read_no_lock(weak_table_t *weak_table, id *referrer_id) 
{
    objc_object **referrer = (objc_object **)referrer_id;
    objc_object *referent = *referrer;
    if (referent->isTaggedPointer()) return (id)referent;
    //...
}複製代碼
inline bool 
objc_object::isTaggedPointer() 
{
#if SUPPORT_TAGGED_POINTERS
    return ((uintptr_t)this & TAG_MASK);
#else
    return false;
#endif
}複製代碼

這裏取對象的值作了一些判斷若是是tagged pointer , 對象的值就是指針若是非tagged pointer , 對象的值是指針指向的內存區域中的值

相關文章
相關標籤/搜索