天天看點

《編寫高品質代碼:改善Objective-C程式的61個建議》——建議10:在64位環境下盡可能利用标記指針

本節書摘來自華章出版社《編寫高品質代碼:改善objective-c程式的61個建議》一 書中的第2章,作者:劉一道,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

在mac os x 10.6(雪豹)中開始支援64位,如今最新版本iphone 5s也開始采用arm64架構。在64位化的過程中,其中一個比較關鍵的改進就是,mac os 10.7(美洲虎)和ios 7的64位環境先後引入了标記(tagged)指針。

下面就簡單地來介紹一下标記(tagged)指針。在介紹标記(tagged)指針之前有必要介紹一下指針位址對齊概念和64位環境的一些變化。

指針位址對齊

在32位環境下,要讀取一個32位整數,如果這個32位整數在記憶體位址為0x00000002-0x00000006(僅作舉例,這個位址一般是被系統保留的)的記憶體上,讀取這個整數會消耗2個cpu周期,而如果這個數在0x00000004~0x00000008的記憶體上隻需要一個cpu周期。為了加快記憶體的cpu通路,程式都使用了指針位址對齊概念。指針位址對齊就是指在配置設定堆中的記憶體時往往采用偶數倍或以2為指數倍的記憶體位址作為位址邊界。幾乎所有系統架構,包括mac os和ios,都使用了位址對齊概念。

運作這段代碼後,得到了如下結果:

可以看到,a和b指針的最後4位都是0,雖然a隻占用31個位元組,但是a和b的位址卻相差16個位元組。因為ios中是以16個位元組為記憶體配置設定邊界的,或者說ios的指針位址對齊是以16個位元組為對齊邊界的。進一步說,ios中配置設定的記憶體位址最後4位永遠都是0。

64位位址

iphone 5s中采用了arm64的cpu,同時也支援了64位的app。64位app中指針大小也擴大到64位,就是理論上可以支援最大264位元組(達千萬t位元組)的記憶體位址空間。而對于大多數應用來說,這麼大的位址空間完全是浪費的。也就是說,64位環境下,記憶體位址的前面很多位一般都是0。

标記(tagged)指針

由于指針位址對齊概念和64位超大位址的出現,指針位址僅僅作為記憶體的位址是比較浪費的,故此,可以在指針位址中儲存或附加更多的資訊。這就引入了标記(tagged)指針概念。标記(tagged)指針是指那些指針中包含特殊屬性或資訊的指針。其中指針對齊概念可以來辨別一個指針是否是标記(tagged)指針及相關類型,64位的位址指針又可以提供儲存額外資訊的足夠空間。如今,ios 7的64位環境和mac os 10.7(lion)中開始引入了标記(tagged)指針。

标記(tagged)指針對nsnumber的優化

标記(tagged)指針一個比較典型的應用就是nsnumber。在64位環境下,對于一般的數字,nsnumber不用再配置設定記憶體了。現在,看看nsnumber是如何運用标記(tagged)指針的:

在64位模拟器中運作後,得到了如下結果:

可以看出number3、number4和number9的值前4位都是0xb,後4位都是0x2(指針的tag),中間就是實際的取值。是以,這些nsnumber已經不需要再配置設定記憶體(指堆中記憶體)了,直接可以把實際的值儲存到指針中,而無須再去通路堆中的資料。這無疑提高了記憶體通路速度和整體運算速度。

也就是說,标記(tagged)指針本身就可以表示一個nsnumber了,在64位環境下運作這段代碼:

會輸出如下結果:

那麼,如果一個數超過了标記(tagged)指針所能表示的範圍,系統會怎麼處理?看看這段代碼:

可以看出numberbig指針最後4位都是0,應該是配置設定在堆中的對象。是以,如果nsnumber超出了标記(tagged)指針所能表示的範圍,系統會自動采用配置設定成對象,可以根據指針的最後4位是否為0來區分。

标記(tagged)指針對isa指針優化

檢視nsobject類的頭檔案,你會發現這段定義:

所有類都繼承自nsobject,是以每個對象都有一個isa指針指向它所屬的類。在32位和64位的環境下, isa指針會産生不同的變化。

在32位環境下,對象的引用計數都儲存在一個外部的表中,而對引用計數的增減操作都要先鎖定這個表,操作完成後才解鎖。這個效率是非常慢的。

而在64位環境下,isa也是64位,實際作為指針部分隻用到其中的33位,剩餘的部分會運用到标記(tagged)指針的概念。其中19位将儲存對象的引用計數,這樣對引用計數的操作隻需要原子的修改這個指針即可。如果引用計數超出19位,才會将引用計數儲存到外部表,而這種情況往往是很少的,是以效率将會大大提高。

 要點

(1)利用标記(tagged)指針,可以在指針位址中儲存或附加更多的資訊。

(2)利用标記(tagged)指針處理nsnumber,直接可以把實際的值儲存到指針中,而無須再去通路堆中的資料,可提高記憶體通路速度和整體運算速度。

(3)在32位和64位的環境下,isa指針會産生不同的變化。在64位環境下,标記(tagged)指針可加快isa指針的處理效率。

繼續閱讀