iOS底層原理探究- NSObject 所佔內存

iOS底層原理探究- NSObject 所佔內存

面向對象的Objective-C

咱們平時寫的 OC 代碼底層實現爲 C/C++ 代碼,由於 RuntimeOC 具有了面向對象的特色,然後底層的 C/C++ 會轉換成底層的 彙編 代碼,最終被被解析成計算機能識別的 機器語言 。而 OC 中的類,正是正是基於 C/C++ 的結構體實現的。咱們能夠經過 clang 命令將咱們平時所寫的 OC 代碼轉換爲 C/C++ 代碼。這是轉換代碼:objective-c

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc 源文件名 -o 目標文件名
複製代碼

若是須要連接其餘框架,使用 -framework參數 好比 -framework UIKitbash

如: 咱們進入源文件所在的目錄,執行 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp 會在當前目錄生成一個main.cpp的文件,這就是一個最簡單的OC文件的 C++ 實現。app

經過轉換以後咱們很容易找到 NSObject 類的真正實現:框架

struct NSObject_IMPL {
	Class isa;
};
複製代碼

只有一個 名爲 isaClass 實例。繼續探尋 Class 的聲明:iphone

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
複製代碼

發現 Class 其實是一個指向 objc_class 的結構體指針。spa

也就是說 NSObject 最終聲明爲一個 指向結構體 objc_class 的名爲 isa 的結構體指針。既然是指針,在32位系統中佔 4個 字節,在64位系統中佔 8 個字節。如何查看本身的Mac是多少位呢?能夠在終端 輸入 uname -a 若末尾顯示 x86_64 則表明是64位系統,若是末尾顯示 i686 則表明是32 系統。目前咱們所使用的大多都是 64 位。指針

使用 Runtime 中 class_getInstanceSize 輸出一個類的實例對象的成員變量的大小
NSObject *obj = [[NSObject alloc] init];
        NSLog(@"%zd",class_getInstanceSize([obj class]));
複製代碼

輸出: code

Snip20180529_3

因而可知,一個 NSObject 只有一個成員變量 即 isa,它所佔 8 個字節的大小。 咱們可經過 objc4源碼得出此結論。cdn

Snip20180529_4

Snip20180529_5

Class's ivar size rounded up to a pointer-size boundary. 一個類的全部成員變量所佔用的空間。對象

那在 OC 中一個 NSObject 對象佔用8個字節嗎?答案是否認的,咱們繼續分析。

使用 malloc_size(const void *ptr) 輸出一個類實際分配的內存大小
NSObject *obj = [[NSObject alloc] init];
        NSLog(@"%zd",malloc_size((__bridge const void *)obj));
複製代碼

輸出:

2018-05-29 07:40:24.270554+0800 XWTest0[25108:1196172] 16
複製代碼
此外咱們也能夠用這種方式來證實一個NSObject對象佔 16 個字節

咱們知道在 OC 的對象實例中, 真正給對象分配內存的方式是

+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
複製代碼

咱們能夠探究 allocWithZone 方法的底層實現, 一樣查看Apple開源的OC源碼 objc4源碼

Snip20180602_1

Snip20180602_2

Snip20180602_3

Snip20180602_4

全部的OC對象至少爲16字節。進一步證實 NSObject類實際所佔用的內存空間爲 16 個字節

相關文章
相關標籤/搜索