iOS中OC對象的本質

一個OC對象在內存中如何布局?以及一個NSObject對象占用多少內存?

我們知道OC的底層語言是c/c++我們平時編寫的OC代碼其實都會轉成c/c++的代碼.
舉個??

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
    }
    return 0;
}

在終端輸入clang -rewrite-objc main.m -o main.cpp 回車會生成C++,
但是該命令并沒有指定平臺(mac,windows,iOS),在不同的平臺會生成不同的代碼,OC代碼是一樣的.如果沒有指定平臺,生成的代碼文件會比較大.所以我們需要將代碼生成我們ios支持的C++代碼,更優(yōu)選擇是使用這條命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc mian.m -o main-arm64.cpp.

  • 在終端cd到mian.m的同級目錄.
  • 用于xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp回車.
  • 之后會在main.m的同級目錄看到新增了一個main-arm64.cpp的文件
  • 打開文件會看見大量的代碼,使用快捷鍵command + ↓,會看到我們創(chuàng)建的NSObject代碼.

解析

  • xcrun -sdk iphoneos利用xcrun 指定sdk 支持編譯iphoneos平臺.
  • clangode內置的llvm的編譯器前端.
  • -arch arm64 arch是架構的意思(指定架構),iOS架構分別是:模擬器(i386),真機分別是 32bit(armv7) 和b4bit(arm64) 從iPhone6 開始基本上是64的系統(tǒng).所以這里選擇 arm64.
  • -rewrite-objc mian.m 重寫main.m中的OC代碼.
  • -o main-arm64.cpp, -o 代表output,以main-arm64.cpp文件的輸出.
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));

    }
    return 0;
}

接著將生成的文件拖拽到項目中去.

步驟.png

之后可以編譯通過了.
cpp文件中搜索NSObject_IMPL.
Snip20181019_3.png
.
實際上上述的NSObject_IMPL就是代碼中的一個NSObject對象的底層實現,也就是OC中的NSObject類的底層實現是C++的結構體支撐的.更為清楚的了解,我們可以Jump to Defintion
Snip20181019_5.png

進入NSObject.h文件中看OC是如何定義的.
Snip20181019_6.png

可以看到OC的定義也是一個結構體.
Snip20181019_10.png

在結構體中包含了一個 Class isa;的指針,該Class類型是typedef struct objc_class *Class;是一個指向結構體的指針,也即是Class是一個指針.

注意:指針類型在64位的操作系統(tǒng)是占8個字節(jié)數,在32為系統(tǒng)中占4個字節(jié)數.

總結:一個OC對象在內存中就是一個結構體,該結構體中只有一個isa成員,該isa指針占8個字節(jié)數.

思考:一個OC對象在內存中如何布局?
答:一個OC對象在底層中就是一個結構體.
思考:一個NSObject對象占用多少內存?
???(如果回答8個字節(jié)數的話,還是不夠深入.)

下面在代碼中可以引入系統(tǒng)框架來看下輸出的結果是什么.

#import <objc/runtime.h> // 通過runtime 可以獲取一個實例對象的大小
#import <malloc/malloc.h>// iOS中分配內存的框架
// NSObject Implementation
struct NSObject_IMPL {
    Class isa;
};

int main(int argc, const char * argv[]) {
    @autoreleasepool {

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

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

    }
    return 0;
}

輸出

2018-10-19 18:31:16.729754+0800 MLOC_NSObject[3518:154054] ---> 8
2018-10-19 18:31:16.732002+0800 MLOC_NSObject[3518:154054] ===> 16

結果是不一樣的,通過malloc_size可以得到實際的分配內存的大小,但是通過class_getInstanceSize根據名字可以猜測是獲取實例對象的大小,(那么就是NSObject的對象嗎?),接下來我們可以看下class_getInstanceSize蘋果官方是如何實現的(其中Runtime部分代碼是開源的).
蘋果開源代碼

Snip20181019_13.png

下載最新代碼.打開源碼搜索class_getInstanceSize
Snip20181019_14.png

可以看到class_getInstanceSize的實現了內部調用了alignedInstanceSize點擊進入查看下

Snip20181019_15.png

我們可以看到該方法返回的是一個實例成員變量的大小,并不是一個實例對象的大小,那么系統(tǒng)為什么會分配給我們16個字節(jié)數呢?
我們在初始化對象的時候NSObject *obj = [[NSObject alloc] init];通過alloc來分配內存的,所有可以通過查看的內部實現是怎么樣.
Snip20181019_22.png

一層層進入最終可以看到下面的方法.得出結論Core Foundation object 對象必須至少16的字節(jié)數

size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // Core Foundation object 對象必須至少16的字節(jié)數
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }

總結:一個NSObject對象分配了16個字節(jié)數,真正使用的只有8個字節(jié)數,

思考:一個NSObject對象占用多少內存?
正確答案:系統(tǒng)分配了16個字節(jié)給NSObject對象,(在我們的實際開發(fā)中直接通過
malloc_size函數獲得,不需要理會).
但是NSObject對象內部只使用了8個字節(jié)數(在64bit環(huán)境下可以通過class_getInstanceSize函數獲得)

小碼哥底層原理總結

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

相關閱讀更多精彩內容

  • 近期越來越感觸一個重要的能力——深度思考能力。 記得兩句風格類似話——你要相信,你所看到的世界,一定是表象;你要相...
    落沙夕陽閱讀 906評論 1 9
  • 2016年12月18日 衆(zhòng)緣?尚品 唐卡的材質特點和表現決定了唐卡的品種。早期的唐卡使用的顏料多為礦物質和植物顏...
    衆(zhòng)緣尚品閱讀 5,643評論 0 1
  • 十月中以來,溫哥華變成了雨哥華,綿綿不絕的秋雨下個不停,甚至創(chuàng)造了十一月份的連續(xù)下雨記錄,我們的健行活動也因此停頓...
    游閑溫哥華閱讀 1,366評論 0 2

友情鏈接更多精彩內容