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)。

層層點進(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ù)獲得)