題記
這系列的目的是回顧一下學(xué)到的知識,對OC底層原理作一翻探究,以及對一些常見的底層原理面試題作一次總結(jié)。
準(zhǔn)備工作
-
如題目所示,我們新建一個demo來探究:一個NSObject對象占多大內(nèi)存
如大部分iOS開發(fā)者所知,OC的底層是C/C++,為了清楚了解NSObject的本質(zhì),我們可以看看底層是怎么實現(xiàn)。
- 進(jìn)入mian.m文件所在的路徑,打開terminal
- 輸入以下指令把OC代碼轉(zhuǎn)成C++(因為mac平臺下使用的是arm64架構(gòu),實際情況可以選擇相應(yīng)的架構(gòu))
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp

-
我們可以得到一個main-arm64.cpp 文件
- 把cpp文件直接拽入Xcode,為了不顯示報錯信息,我們不讓它參與編譯
探究
-
點擊NSObject我們可以看到OC的定義
-
在main.cpp文件里面搜索NSObject_IMPL,我們可以看到NSObject轉(zhuǎn)成C++后的本質(zhì)是一個結(jié)構(gòu)體
- 我們再點擊Class進(jìn)去,可以看到其實它就是一個指針。那么我們知道在64位環(huán)境下,它占8個字節(jié)。
論證
- 有了這個推論,我們還可以進(jìn)一步論證我們的觀點,這里我們用到runtime,也就是運行時的一個方法class_getInstanceSize
- 為了驗證推論的準(zhǔn)確性,我們先找到蘋果開源的源碼,打開瀏覽器
http://opensource.apple.com/tarballs/搜索`objc
-
點擊進(jìn)去,我們找到數(shù)字最大的一個,一般來說也是最新的一個
-
下載壓縮包解壓后并打開
- 搜索
class_getInstanceSize,并在.mm文件里面可以看到它的實現(xiàn)
-
點擊3中的alignedInstanceSize()方法,我們可以看到進(jìn)一步注釋,這個方法返回的是類對象成員變量所占用的內(nèi)存大小
- 所以通過調(diào)用runtime的這個方法我們可以看到,NSObject類對象所占用的內(nèi)存大小為8個字節(jié)
疑問
- 這個就是最終結(jié)果了嗎?不用急著下定義。我們還有個叫malloc_size的方法可以查看系統(tǒng)分配內(nèi)存的大小。由于這里需要傳一個C的指針,所以我們打印obj的時候需要橋接一下。然后我們會發(fā)現(xiàn),返回的大小是16而不是8!
總結(jié)
-
為什么會造成這個不一致呢?我們還是要從源碼入手分析,首先還是在objc的源碼里面搜索allocWithZone這個方法,查看創(chuàng)建一個對象是內(nèi)存是怎么分配
- 我們點擊進(jìn)入
class_createInstance這個方法,看到返回的是_class_createInstanceFromZone方法,我們再次點擊進(jìn)去就能很快鎖定我們需要的信息:size
-
我們可以從注釋看到,所有對象至少分配16 bytes 的大小,從方法實現(xiàn)來看,如果size < 16,則size = 16















