Objective-C對象的本質(zhì)
我們知道Objective-C代碼冀瓦,底層實現(xiàn)其實都是C\C++代碼必搞,所以這里為了窺探Objective-C的本質(zhì)屠列,我們可以將Objective-C代碼轉(zhuǎn)換為C\C++代碼
(PS:在這里我指定了架構(gòu)為arm64)
(PPS:如果需要連接其他框架没佑,需要使用-framework參數(shù)原叮。比如-framework UIKit):
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 輸出的CPP文件
OC對象的本質(zhì)
// NSObject 的底層實現(xiàn)
struct NSObject_IMPL {
Class isa;
};
?
// isa 本質(zhì)就是一個指向 objc_class 結(jié)構(gòu)體的指針
typedef struct objc_class *Class;
可以得出抚恒,其實NSObject的對象和類主要是基于C/C++的結(jié)構(gòu)體來實現(xiàn)的咱台。
OC對象的內(nèi)存分配
那么isa的本質(zhì)是一個指針,一個NSObject對象中俭驮,只包含一個isa指針回溺,那么在32位的環(huán)境下春贸,一個NSObject對象,在32位的環(huán)境下遗遵,應(yīng)該是占4個字節(jié)萍恕,在64位的環(huán)境下,應(yīng)該占8個字節(jié)车要。然而實際上并非如此允粤,下面來分析一下OC對象實際的占用內(nèi)存的情況。
獲取內(nèi)存大小函數(shù)調(diào)用
這里先說兩個函數(shù):
1.如下函數(shù)調(diào)用之后翼岁,輸出的size為8类垫,表示的是,創(chuàng)建一個實例對象琅坡,至少需要多少內(nèi)存悉患?
#import <objc/riuntime.h>
// 獲得 NSObject 實例對象的成員變量所占用的大小 >> 8
class_getInstanceSize([NSObject class]);
2.如下函數(shù)調(diào)用之后,輸出的size為16榆俺,表示的是售躁,創(chuàng)建一個實例對象,實際分配了多少內(nèi)存茴晋?
#import <malloc/malloc.h>
// 獲得 obj 指針?biāo)赶騼?nèi)存的大小 >> 16
malloc_size((__bridge const void *)obj);
我們可以通過Xcode的調(diào)試器陪捷,查看實時內(nèi)存。
從如下調(diào)試內(nèi)容中晃跺,我們可以看到 objc 的內(nèi)存地址是:objc -> 0x103c06e90
可以看出揩局,NSObject 的實例對象 objc 在內(nèi)存中,實際使用內(nèi)存的大小確實是8個字節(jié)掀虎,但是系統(tǒng)給分配了16個字節(jié)凌盯。
OC源碼分析
接下來通過蘋果開源的源碼來分析一下(源碼下載地址如下):
https://opensource.apple.com/tarballs/objc4/
class_getInstanceSize()
在源碼中,我們搜索 class_getInstanceSize() 實現(xiàn)方法烹玉,實現(xiàn)方法如下圖所示:
malloc_size()
allocWithZone
NSObject *objc = [[NSObject alloc] init];
上述實例化一個對象的方法驰怎,看出實際分配內(nèi)存空間是由 alloc 方法分配的,我們在下載的 objc 的源碼中搜索 allocWithZone 方法的實現(xiàn)二打。
層層點(diǎn)進(jìn)去查看方法县忌,最后通過注釋和代碼可以發(fā)現(xiàn),CF:CoreFoundation继效,規(guī)定返回 size 最小為16症杏。
綜上所述:
一個NSObject對象占用多少內(nèi)存?
系統(tǒng)分配了16個字節(jié)給 NSObject 對象(通過 malloc_size 函數(shù)獲得)
但 NSObject 對象內(nèi)部只使用了8個字節(jié)的空間(64bit環(huán)境下瑞信,可以通過 class_getInstanceSize 函數(shù)獲得)