iOS源碼閱讀必備知識(shí)之Tagged Pointer
Tagged Pointer 介紹
蘋果對(duì)于Tagged Pointer特點(diǎn)的介紹:
- Tagged Pointer專門用來(lái)存儲(chǔ)小的對(duì)象,例如NSNumber和NSDate
- Tagged Pointer指針的值不再是地址了,而是真正的值。所以,實(shí)際上它不再是一個(gè)對(duì)象了,它只是一個(gè)披著對(duì)象皮的普通變量而已。所以,它的內(nèi)存并不存儲(chǔ)在堆中,也不需要malloc和free。
- 在內(nèi)存讀取上有著3倍的效率,創(chuàng)建時(shí)比以前快106倍。
為什么要引入Tagged Pointer
iPhone5s 采用64位處理器。對(duì)于64位程序,我們的數(shù)據(jù)類型的長(zhǎng)度是跟CPU的長(zhǎng)度有關(guān)的。
這樣就導(dǎo)致了 一些對(duì)象占用的內(nèi)存會(huì)翻倍。
同時(shí) 維護(hù)程序中的對(duì)象需要 分配內(nèi)存,維護(hù)引用計(jì)數(shù),管理生命周期,使用對(duì)象給程序的運(yùn)行增加了負(fù)擔(dān)。
Tagged Pointer
為了改進(jìn)上面提到的內(nèi)存占用和效率問題,蘋果提出了Tagged Pointer對(duì)象。由于NSNumber、NSDate一類的變量本身的值需要占用的內(nèi)存大小常常不需要8個(gè)字節(jié),拿整數(shù)來(lái)說(shuō),4個(gè)字節(jié)所能表示的有符號(hào)整數(shù)就可以達(dá)到20多億(注:2^31=2147483648,另外1位作為符號(hào)位),對(duì)于絕大多數(shù)情況都是可以處理的。
我們可以將一個(gè)對(duì)象的指針拆成兩部分,一部分直接保存數(shù)據(jù),另一部分作為特殊標(biāo)記,表示這是一個(gè)特別的指針,不指向任何一個(gè)地址。所以,引入了Tagged Pointer對(duì)象之后,64位CPU下NSNumber的內(nèi)存圖變成了以下這樣:
Tagged Pointer
測(cè)試
#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(假設(shè)27為標(biāo)記) 0x1 就是number 的值。
0x227
0x327
都有這種規(guī)律
numberLager 存儲(chǔ)的值為MAXFloat 顯然超過了tagged pointer 可以存儲(chǔ)的范圍。
所以打印的地址是單純的指針地址,指向存儲(chǔ)numberLager的內(nèi)存地址。
對(duì)于isa指針的影響
因?yàn)閠agged pointer 不是一個(gè)真正的對(duì)象,如果使用isa指針在編譯時(shí)會(huì)報(bào)錯(cuò)。
如圖:
提示我們改為object_getClass()
object_getClass()中做了相應(yīng)的處理
由于object_getClass()沒有對(duì)應(yīng)的實(shí)現(xiàn),只能從其他地方窺探一二
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 }
這里取對(duì)象的值做了一些判斷
如果是tagged pointer , 對(duì)象的值就是指針
如果非tagged pointer , 對(duì)象的值是指針指向的內(nèi)存區(qū)域中的值
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
iOS實(shí)現(xiàn)視頻壓縮上傳實(shí)例代碼
本篇文章主要介紹了iOS實(shí)現(xiàn)視頻壓縮上傳實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2017-04-04IOS實(shí)現(xiàn)微信朋友圈相冊(cè)評(píng)論界面的翻轉(zhuǎn)過渡動(dòng)畫
現(xiàn)在很多人幾乎每天都離不開微信,大家有沒有發(fā)現(xiàn)在點(diǎn)開微信相冊(cè)的時(shí)候,想要在相冊(cè)圖片界面跳轉(zhuǎn)查看點(diǎn)贊和評(píng)論時(shí),微信會(huì)采用界面翻轉(zhuǎn)的過渡動(dòng)畫來(lái)跳轉(zhuǎn)到評(píng)論界面,點(diǎn)擊完成又會(huì)翻轉(zhuǎn)回到圖片界面,這不同于一般的導(dǎo)航界面滑動(dòng)動(dòng)畫,于是學(xué)著做了一下,有需要一起看看。2016-08-08iOS開發(fā)中蘋果輸入手機(jī)號(hào)變用戶的名字
今天我們的用戶輸入手機(jī)號(hào)之后變成了用戶的名字,沒辦法獲取驗(yàn)證碼,因?yàn)槭謾C(jī)格式不對(duì)。下面通過本文給大家分享開發(fā)中蘋果輸入手機(jī)號(hào)變用戶的名字,需要的朋友可以參考下2017-05-05IOS 獲取網(wǎng)絡(luò)圖片大小實(shí)例詳解
這篇文章主要介紹了IOS 獲取網(wǎng)絡(luò)圖片大小實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06iOS基于 UILabel實(shí)現(xiàn)文字添加描邊功能
這篇文章主要介紹了iOS基于 UILabel實(shí)現(xiàn)文字添加描邊功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10iOS中長(zhǎng)按調(diào)出菜單組件UIMenuController的使用實(shí)例
UIMenuController即是用來(lái)制作我們平時(shí)對(duì)文本長(zhǎng)按屏幕后顯示出的復(fù)制粘貼等選項(xiàng)菜單,下面就來(lái)詳細(xì)整理一下iOS中長(zhǎng)按調(diào)出菜單組件UIMenuController的使用實(shí)例:2016-06-06