iOS底層原理探索篇 主要是圍繞底層進行
源碼分析
-LLDB調試
-源碼斷點
-彙編調試
,讓本身之後回顧複習的😀😀c++目錄以下:算法
來看下圖代碼: 架構
先補充一點sizeof()知識:sizeof()是獲取類型的大小,它是一個運算符,而不是方法,在編譯的時候就是一個肯定的數據.app
Interger data type | ILP32 size | ILP64 size |
---|---|---|
char | 1 byte | 1 byte |
BOOL,bool | 1 byte | 1 byte |
short | 2 byte | 2 byte |
float | 4 byte | 4 byte |
CGFloat | 8 byte | 8 byte |
int | 4 byte | 4 byte |
long | 4 byte | 8 byte |
long long | 8 byte | 8 byte |
double | 8 byte | 8 byte |
pointer | 4 byte | 8 byte |
結構體 | 最大屬性內存的倍數 | 最大屬性內存的倍數 |
接下來咱們來看一個問題:CGPoint在內存中如何分配? CGPoint在OC中是一個結構體,結構體通常採用內存對齊的方式分配.iphone
內存對齊的原則源碼分析
數據成員對齊規則:結構(struct)(或聯合(union))的數據成員,第一個數據成員放在offset爲0的地方,之後每一個數據成員存儲的起始位置要從該成員大小或者子成員大小(只要該成員有子成員,好比說是數組,結構體等)的整數倍開始(好比int爲4字節,則要從4的整數倍地址開始存儲)存儲.(好比min(當前開始的位置m n) m = 9 n = 4,9不是4的整數倍,那麼要捨棄填充 9 10 11,從12(12是4的整數倍) 開始存儲).
結構體做爲成員:若是一個結構裏面有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍地址開始存儲.(struct A裏存有struct B,B裏有char,int,double等元素,那B應該從8的整數倍開始存儲.)但在肯定複合類型成員的偏移位置時則是將複合類型做爲總體看待。
結構體的總大小,也就是sizeof的結果:必須是其內部最大成員的整數倍,不足的要補齊.
總結:結構體的大小等於最後一個成員的偏移量加上其大小再加上末尾的填充字節數目.即:sizeof(struct) = offset(last item) + sizeof(last item) + sizeof( training padding)
前面的地址必須是後面的地址整數倍,不是就補齊。
整個結構體的地址必須是最大字節的整數倍。
在肯定複合類型成員的偏移位置時則是將複合類型做爲總體看待。
結構體的sizeof() 長度用 補、偏、長 與 結構體長度按成員最大長度對齊 結合的方式來計算有助於咱們理解內存對齊的原則. 例一:
例二:成員個數與每一個成員類型都同樣,只不過順序不同,佔內存大小就不同。
例三:複合型結構體(結構體裏嵌套結構體)
現代計算機中內存空間都是按照byte劃分的,從理論上講彷佛對任何類型的變量的訪問能夠從任何地址開始,但實際狀況是在訪問特定類型變量的時候常常在特定的內存地址訪問,這就須要各類類型數據按照必定的規則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。 對齊的做用和緣由:各個硬件平臺在對存儲空間的處理上有很大的不一樣。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。好比有些架構的CPU在訪問一個沒有進行對齊的變量的時候會發生錯誤,那麼在這種架構下編程必須保證字節對齊.其餘平臺可能沒有這種狀況,可是最多見的是若是不按照適合其平臺要求對數據存放進行對齊,會在存取效率上帶來損失。好比有些平臺每次讀都是從偶地址開始,若是一個int型(假設爲32位系統)若是存放在偶地址開始的地方,那麼一個讀週期就能夠讀出這32bit,而若是存放在奇地址開始的地方,就須要2個讀週期,並對兩次讀出的結果的高低字節進行拼湊才能獲得該32bit數據。顯然在讀取效率上降低不少。
問題:一個OC對象佔據了多少內存空間呢?下面讓咱們用代碼實際驗證一下.
clang -rewrite-objc main.m -o main.cpp
/***rewrite表明 重寫
*-o表明 輸出
*cpp表明 c++(c plus plus)
**/
複製代碼
須要注意這種方式沒有指定運行平臺和架構模式,咱們能夠經過命令行設置參數,來指定運行平臺和架構模式
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
/***xcrun表明 xcode
* iphoneos表明 運行在iPhone上
*-arch表明 架構模式,arm64參數表明64位的架構模式
**/
複製代碼
生成的main.cpp 文件就是main.m轉換c++後的文件,直接拖拽到工程中,就能夠查看底層實現了。咱們在main.cpp 文件中搜索NSObjcet,能夠找到NSObjcet_IMPL(IMPL即 implementation 的縮寫,表明實現)。
至此咱們換一份源碼分析:
malloc
的源碼中搜索
nano_calloc,於
nano_calloc.c文件中找到該方法,其中的核心代碼**_nano_malloc_check_clear**,進行內存申請,而且返回一個成熟的指針ptr
segregated_next_block
不斷遞歸去尋找合適的內存空間:
對象內存的申請按照8字節對齊,不滿16字節按照16字節計算;可是實際上calloc實際開闢內存的時候,則是進行了16字節對齊. 最後附上calloc流程圖: