一.先來看看我們平時接觸的NSObject
- NSObject *objc = [[NSObject alloc]init]的本質
在內存中,這行代碼就把objc轉在底層實現中轉成了一個結構體,其底層C++編譯成結構體為:
struct NSObject_IMPL {
Class isa;
};
在64位機中,一個isa占8個字節,在32位機中,一個isa占4個字節(當然蘋果后面的機型都是64位的,這里我們著重講解64位機)
- 我們先來看看這個創建好的objc占多少個字節
int main(int argc, char * argv[]) {
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
//定義一個objc
NSObject *objc = [[NSObject alloc]init];
//打印內存
NSLog(@"tu-%zd",class_getInstanceSize([NSObject class]));
NSLog(@"tu-%zd",malloc_size((__bridge const void *)(objc)));
}
}
其打印結果為objc打印結果
-
為什么一個是8一個是16
我們先來認識一下class_getInstanceSize、malloc_size的區別
1.class_getInstanceSize:是一個函數(調用時需要開辟額外的內存空間),程序運行時才獲取,計算的是類的大小(至少需要的大小)即實例對象的大小->結構體內存對齊
2.創建的對象【至少】需要的內存大小不考慮malloc函數的話,內存對齊一般是以【8】對齊
3.#import <objc/runtime.h>使用這個函數時倒入runtime運行時-
malloc_size:堆空間【實際】分配給對象的內存大小 -系統內存對齊
- 在Mac、iOS中的malloc函數分配的內存大小總是【16】的倍數 即指針指向的內存大小
- import <malloc/malloc.h>使用時倒入這個框架
- sizeof:是一個運算符,獲取的是類型的大小(int、size_t、結構體、指針變量等),這些數值在程序編譯時就轉成常數,程序運行時是直接獲取的
看到上面對兩個函數的認識,應該知道為什么輸出的一個是8,一個是16了吧,當內存申請<16時,在底層分配的時候,系統會默認最低16個字節,系統給objc16個字節,而objc用到的是8個字節(沒添加任何成員變量之前)
二.內存對齊
- 在上面的基礎上我們新建一個類Student繼承NSObject,那么對于student的底層C++編譯實現就變成了:
struct Student {
struct NSObject_IMPL NSOBJECT_IVARS;
};
也就是說,繼承關系,子類直接將父類的isa引用進來
- 對于class_getInstanceSize(也就是類本質的內存對其)
1.在student中創建成員變量:
@interface Student : NSObject
{
@public
int _age;
int _no;
int _tc;
}
@end
其底層C++編譯結構體就變成了
struct Student {
struct NSObject_IMPL NSOBJECT_IVARS;
int _age;
int _no;
int _tc;
};
- 打印結果:
//定義一個objc
Student *objc = [[Student alloc]init];
//打印內存
NSLog(@"tu-%zd",class_getInstanceSize([Student class]));
NSLog(@"tu-%zd",malloc_size((__bridge const void *)(objc)));
2020-09-08 12:35:27.158568+0800 OC底層[1549:79836] tu-24
2020-09-08 12:35:27.159046+0800 OC底層[1549:79836] tu-32
- 先來說說24的由來
由于創建對象的時候,內存是以8對齊,上面我們講到一個對象里面包含了一個isa占8個字節,對于student來說它有四個成員變量,isa,age,no,tc,共占8+4+4+4=20字節,但是由于內存以8對齊的原因,我們看到的輸出是24,結構體8位對齊
所以class_getInstanceSize在計算實例大小的時候就是24,其白色區域表示空出了四個字節
-
再來看看32的由來
上面我們說到malloc_size指的是實際堆分配的空間,它以16字節對齊
堆內存對齊
可以看到,空白的區域為空出了12個字節,總共為32個字節
三.添加屬性
- 添加屬性
@interface Student : NSObject
{
@public
int _age;
int _no;
int _tc;
}
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *array;
@end
其在底層C++編譯就變成了
struct Student {
struct NSObject_IMPL NSOBJECT_IVARS;
int _age;
int _no;
int _tc;
NSString _name;
NSArray _array;
};
默認的會將屬性生成的_name添加進結構體中,計算相應的大小