一.先來看看我們平時接觸的NSObject
- NSObject *objc = [[NSObject alloc]init]的本質(zhì)
在內(nèi)存中赋铝,這行代碼就把objc轉(zhuǎn)在底層實現(xiàn)中轉(zhuǎn)成了一個結(jié)構(gòu)體猬膨,其底層C++編譯成結(jié)構(gòu)體為:
struct NSObject_IMPL {
Class isa;
};
在64位機(jī)中瓤漏,一個isa占8個字節(jié),在32位機(jī)中,一個isa占4個字節(jié)(當(dāng)然蘋果后面的機(jī)型都是64位的,這里我們著重講解64位機(jī))
- 我們先來看看這個創(chuàng)建好的objc占多少個字節(jié)
int main(int argc, char * argv[]) {
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
//定義一個objc
NSObject *objc = [[NSObject alloc]init];
//打印內(nèi)存
NSLog(@"tu-%zd",class_getInstanceSize([NSObject class]));
NSLog(@"tu-%zd",malloc_size((__bridge const void *)(objc)));
}
}
其打印結(jié)果為
-
為什么一個是8一個是16
我們先來認(rèn)識一下class_getInstanceSize、malloc_size的區(qū)別
1.class_getInstanceSize:是一個函數(shù)(調(diào)用時需要開辟額外的內(nèi)存空間)帽揪,程序運(yùn)行時才獲取,計算的是類的大懈ㄕ濉(至少需要的大凶)即實例對象的大小->結(jié)構(gòu)體內(nèi)存對齊
2.創(chuàng)建的對象【至少】需要的內(nèi)存大小不考慮malloc函數(shù)的話,內(nèi)存對齊一般是以【8】對齊
3.#import <objc/runtime.h>使用這個函數(shù)時倒入runtime運(yùn)行時-
malloc_size:堆空間【實際】分配給對象的內(nèi)存大小 -系統(tǒng)內(nèi)存對齊
- 在Mac士飒、iOS中的malloc函數(shù)分配的內(nèi)存大小總是【16】的倍數(shù) 即指針指向的內(nèi)存大小
- import <malloc/malloc.h>使用時倒入這個框架
- sizeof:是一個運(yùn)算符查邢,獲取的是類型的大小(int酵幕、size_t扰藕、結(jié)構(gòu)體、指針變量等)芳撒,這些數(shù)值在程序編譯時就轉(zhuǎn)成常數(shù)邓深,程序運(yùn)行時是直接獲取的
看到上面對兩個函數(shù)的認(rèn)識,應(yīng)該知道為什么輸出的一個是8笔刹,一個是16了吧芥备,當(dāng)內(nèi)存申請<16時,在底層分配的時候舌菜,系統(tǒng)會默認(rèn)最低16個字節(jié)萌壳,系統(tǒng)給objc16個字節(jié),而objc用到的是8個字節(jié)(沒添加任何成員變量之前)
二.內(nèi)存對齊
- 在上面的基礎(chǔ)上我們新建一個類Student繼承NSObject日月,那么對于student的底層C++編譯實現(xiàn)就變成了:
struct Student {
struct NSObject_IMPL NSOBJECT_IVARS;
};
也就是說袱瓮,繼承關(guān)系,子類直接將父類的isa引用進(jìn)來
- 對于class_getInstanceSize(也就是類本質(zhì)的內(nèi)存對其)
1.在student中創(chuàng)建成員變量:
@interface Student : NSObject
{
@public
int _age;
int _no;
int _tc;
}
@end
其底層C++編譯結(jié)構(gòu)體就變成了
struct Student {
struct NSObject_IMPL NSOBJECT_IVARS;
int _age;
int _no;
int _tc;
};
- 打印結(jié)果:
//定義一個objc
Student *objc = [[Student alloc]init];
//打印內(nèi)存
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的由來
由于創(chuàng)建對象的時候爱咬,內(nèi)存是以8對齊懂讯,上面我們講到一個對象里面包含了一個isa占8個字節(jié),對于student來說它有四個成員變量台颠,isa,age,no串前,tc瘫里,共占8+4+4+4=20字節(jié),但是由于內(nèi)存以8對齊的原因荡碾,我們看到的輸出是24谨读,
所以class_getInstanceSize在計算實例大小的時候就是24,其白色區(qū)域表示空出了四個字節(jié)
-
再來看看32的由來
上面我們說到malloc_size指的是實際堆分配的空間坛吁,它以16字節(jié)對齊
可以看到劳殖,空白的區(qū)域為空出了12個字節(jié),總共為32個字節(jié)
三.添加屬性
- 添加屬性
@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;
};
默認(rèn)的會將屬性生成的_name添加進(jìn)結(jié)構(gòu)體中拨脉,計算相應(yīng)的大小