Tagged Pointer是一個(gè)能夠提升性能断傲、節(jié)省內(nèi)存的有趣的技術(shù)
其實(shí)早在在2013年9月织堂,蘋(píng)果推出了iPhone5s,與此同時(shí)徐矩,iPhone5s配備了首個(gè)采用64位架構(gòu)的A7雙核處理器粮宛,為了節(jié)省內(nèi)存和提高執(zhí)行效率,蘋(píng)果提出了Tagged Pointer的概念卖宠。對(duì)于64位程序巍杈,引入Tagged Pointer后,相關(guān)邏輯能減少一半的內(nèi)存占用扛伍,以及3倍的訪(fǎng)問(wèn)速度提升筷畦,100倍的創(chuàng)建、銷(xiāo)毀速度提升刺洒。
問(wèn)題
我們先看看原有的對(duì)象為什么會(huì)浪費(fèi)內(nèi)存鳖宾。假設(shè)我們要存儲(chǔ)一個(gè)NSNumber對(duì)象,其值是一個(gè)整數(shù)逆航。正常情況下鼎文,如果這個(gè)整數(shù)只是一個(gè)NSInteger的普通變量,那么它所占用的內(nèi)存是與CPU的位數(shù)有關(guān)因俐,在32位CPU下占4個(gè)字節(jié)拇惋,在64位CPU下是占8個(gè)字節(jié)的。而指針類(lèi)型的大小通常也是與CPU位數(shù)相關(guān)抹剩,一個(gè)指針?biāo)加玫膬?nèi)存在32位CPU下為4個(gè)字節(jié)撑帖,在64位CPU下也是8個(gè)字節(jié)。
所以一個(gè)普通的iOS程序澳眷,如果沒(méi)有Tagged Pointer對(duì)象胡嘿,從32位機(jī)器遷移到64位機(jī)器中后,雖然邏輯沒(méi)有任何變化钳踊,但這種NSNumber衷敌、NSDate一類(lèi)的對(duì)象所占用的內(nèi)存會(huì)翻倍。如下圖所示:
我們?cè)賮?lái)看看效率上的問(wèn)題箍土,為了存儲(chǔ)和訪(fǎng)問(wèn)一個(gè)NSNumber對(duì)象逢享,我們需要在堆上為其分配內(nèi)存,另外還要維護(hù)它的引用計(jì)數(shù)吴藻,管理它的生命期瞒爬。這些都給程序增加了額外的邏輯,造成運(yùn)行效率上的損失。
Tagged Pointer
為了改進(jìn)上面提到的內(nèi)存占用和效率問(wèn)題侧但,蘋(píng)果提出了Tagged Pointer對(duì)象矢空。由于NSNumber、NSDate一類(lèi)的變量本身的值需要占用的內(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)存圖變成了以下這樣: