一個 NSObject 對象占用多少內(nèi)存空間?

問題:一個NSObject對象占用多少內(nèi)存空間?

首先我們創(chuàng)建一個NSObject對象:

NSObject *obj = [[NSObject alloc] init];

其實這個問題想問的就是obj這個對象所指的指針占用的內(nèi)存大小。

OC的面向?qū)ο蠖际腔?code>C/C++的數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的。

  • OC代碼轉(zhuǎn)化成C/C++代碼
  • NSObject內(nèi)存本質(zhì)
    NSObject內(nèi)存本質(zhì)到底是什么樣子的:
struct NSObject_IMPL {
    Class isa;
};

有上面的代碼可以看出來,NSObject對象在內(nèi)存中就是一個結(jié)構(gòu)體;
而其里面的Class isa,點進去我們可以看到他的定義:

typedef struct objc_class *Class;

實際上,isa就是一個指向結(jié)構(gòu)體的指針。
那么既然isa是個指針,那么他在64位的環(huán)境下占8個字節(jié),在32位環(huán)境上占4個字節(jié)。(我們所使用的是64位架構(gòu)的)
因為這個結(jié)構(gòu)體就isa1個成員,假設(shè)isa的地址是0x100400b70,那么這個結(jié)構(gòu)體的地址就應(yīng)該是isa的地址。所以obj的地址應(yīng)該就是結(jié)構(gòu)體的地址,這個地址占用的內(nèi)存大小就是結(jié)構(gòu)體的大小,即isa的大小,isa這個地址所占用的內(nèi)存大小為8個字節(jié),那么NSObject對象在內(nèi)存中所占用的大小也應(yīng)該是8個字節(jié)。這些就是NSObject內(nèi)存本質(zhì)。

  • 出現(xiàn)問題
    根據(jù)上面NSObject內(nèi)存本質(zhì)的分析,我們應(yīng)該會認(rèn)為NSObject對象在內(nèi)存中占用了8個字節(jié),那么實際上并不是,而是16個字節(jié),為什么呢?讓我們來進一步分析:
    runtime中有個class_getInstanceSize方法獲取實例的大小,首先導(dǎo)入頭文件#import <objc/runtime.h>,那么我們來打印一下看看:
NSObject *obj = [[NSObject alloc] init];
NSLog(@"class_getInstanceSize--%zd", class_getInstanceSize([NSObject class]));

結(jié)果為:

interview-OC對象的本質(zhì)[10809:700450] class_getInstanceSize--8

還有一個獲取內(nèi)存大小的方法,導(dǎo)入頭文件#import <malloc/malloc.h>

NSObject *obj = [[NSObject alloc] init];
NSLog(@"malloc_size--%zd", malloc_size((__bridge const void *)obj));

結(jié)果為:

interview-OC對象的本質(zhì)[10809:700450] malloc_size--16

根據(jù)上面的兩個方法獲取的內(nèi)存大小不一樣,class_getInstanceSize獲取的大小為8個字節(jié),malloc_size獲取的大小是16個字節(jié)。
我們可以去runtime的源碼里面,看一下class_getInstanceSize具體是怎么實現(xiàn)的。OC所有開放的源碼地址https://opensource.apple.com/tarballs
我們找到runtime源碼位置然后下載下來:

runtime源碼

點進去然后下載數(shù)字最大的。
下載完成,打開項目,然后找到class_getInstanceSize的實現(xiàn)。
class_getInstanceSize實現(xiàn)

然后我們點擊去看下alignedInstanceSize實現(xiàn):

// Class's ivar size rounded up to a pointer-size boundary.
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }

可以從注釋上看出來返回的是Class's ivar size,因為NSObject對象只有一個isa成員變量,所以返回的是8個字節(jié)。

看一下alloc的時候分配了多大的內(nèi)存大小,我們還是搜索剛才的源碼allocWithZone然后找到_objc_rootAllocWithZone在這個方法中返回的是class_createInstance(cls, 0),然后跳轉(zhuǎn)進去,返回值再點擊去可以看到instanceSize,再點進去可以看到如下的代碼:

size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }

從上述代碼注釋中可以看到,CF要求至少得返回16個字節(jié)的內(nèi)存大小。

  • 總結(jié)
  • 系統(tǒng)分配了16個字節(jié)NSObject對象(可以通過malloc_size函數(shù)得到);
  • NSObject對象內(nèi)部只使用了8個字節(jié)空間(在64bit環(huán)境下,可以通過class_getInstanceSize函數(shù)獲得)。

iOS面試題匯總

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容