本文主要探索alloc的底層實現(xiàn)原理
- 大家可以通過 Apple source 在 路徑自行下載
objc4-781源碼
首先我們有一個疑問,那就是alloc是如何創(chuàng)建對象,開辟內(nèi)存,并且將對象與內(nèi)存關(guān)聯(lián)起來的呢?我們帶著這些問題打開源碼來一探究竟。
- 1.首先根據(jù)
main函數(shù)中的LGPerson類的alloc方法進入alloc方法的源碼實現(xiàn)(即源碼分析開始)
image.png
2.跳轉(zhuǎn)至_objc_rootAlloc底層實現(xiàn)
image.png
3.跳轉(zhuǎn)至callAlloc

4.接下來流程會走到callAlloc的具體實現(xiàn)

5.進入_class_createInstanceFromZone源碼

這里展示了三個重點方法:
1.cls->instanceSize計算內(nèi)存大小
2.calloc開辟內(nèi)存方式
3.obj->initInstanceIsaisa與類綁定在一起
由此可得出alloc的流程圖如下

問題一:系統(tǒng)是如何計算內(nèi)存空間大小的,即instanceSize的源碼流程
-
跳轉(zhuǎn)到
instanceSize源碼實現(xiàn)如下圖,流程接下來會走進下圖標識處
image.png -
跳轉(zhuǎn)至函數(shù)
fastInstanceSize的源碼實現(xiàn)如圖
image.png -
align16源碼實現(xiàn)
image.png -
align16算法解讀如下圖:其中x為一個對象,所占內(nèi)存8字節(jié)
image.png
此算法說明:由此圖看出,與上之后后四位全部抹零了,也就是說保留了16的倍數(shù),16以下全部抹零。由此得出結(jié)論,此算法的目的就是16字節(jié)對齊。
為什么要16字節(jié)對齊?
- 內(nèi)存對齊是在計算機中排列數(shù)據(jù)、訪問數(shù)據(jù)的一種格式,簡單來說就是前面的地址必須是后面的地址正數(shù)倍,不是就補齊,系統(tǒng)在讀取內(nèi)存的時候,不會隨時改變自己讀取的長度,這么做的目的是為了節(jié)約性能,方便讀取。
- 首先我們知道任何對象都具備一個
isa的屬性(isa是一個結(jié)構(gòu)體指針占8字節(jié)) ,假設(shè)一個對象沒有屬性,沒有內(nèi)存的情況下,就已經(jīng)占了8字節(jié),如果按照8字節(jié)對齊方式進行存儲時會發(fā)現(xiàn)對象是一個挨著一個的,前一個對象挨著后一個對象isa,這樣就容易導(dǎo)致一些訪問錯誤、野指針的問題出現(xiàn)。為了使整個內(nèi)存更加安全,所以預(yù)留了一些位置。
到此我們了解了alloc的源碼實現(xiàn),那么init又做了什么呢?
init原理
-
查看init源碼實現(xiàn)
image.png
image.png
說明
init只返回了self,什么也沒有做,那么 init 有什么作用呢?
這里是利用了工廠設(shè)計模式,init的作用是方便子類自定義重寫,預(yù)留自定義內(nèi)容的接口,給子類自由發(fā)揮的空間。比如array和普通的一個對象,初始化之后,所具有的東西是不一樣的,根據(jù)用戶的需要,可以定制化開發(fā)。給開發(fā)人員提供一個構(gòu)造方法的入口。
new
-
進入new的源碼實現(xiàn)可看到如下圖:
image.png
new是callAlloc和init的結(jié)合,等同于[alloc init],如果子類不想自定義重寫的話,直接可以用new進行初始化開辟內(nèi)存。








