注:文章為自己學(xué)習(xí)李明杰老師的OC底層視頻做的隨手筆記
我們平時(shí)編寫的Objective-C的代碼,底層實(shí)現(xiàn)都是C/C++來實(shí)現(xiàn)的,所以O(shè)bjective-C的面向?qū)ο蠖际腔贑/C++的數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)的,具體是基于什么來實(shí)現(xiàn)的呢?
NSObject的聲明文件可以看到是一個(gè)Class的isa屬性
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
然后編譯成C++的代碼會發(fā)現(xiàn)是一個(gè)結(jié)構(gòu)體
struct NSObject_IMPL {
Class isa;
};
那么一個(gè)NSObject對象占用多少內(nèi)存呢?
實(shí)際上NSObject對象里面只有一個(gè)isa指針,指向一個(gè)結(jié)構(gòu)體
typedef struct objc_class *Class;
一個(gè)指針占用8個(gè)字節(jié),是不是這個(gè)NSObject對象就在內(nèi)存中占用8個(gè)字節(jié)呢
通過malloc的方法獲取創(chuàng)建的NSObject的對象指針?biāo)赶虻膬?nèi)存的大小
NSObject *obj = [[NSObject alloc] init];
NSLog(@"%zd",malloc_size((__bridge const void *)obj));
2019-12-04 20:48:49.819768+0800 test1[29620:292876] 16
答案是16個(gè)字節(jié)
但是對象里面就一個(gè)isa指針,應(yīng)該是占用8個(gè)字節(jié)才是對的,同樣,用runtime方法驗(yàn)證了,對象的成員變量占用了8個(gè)字節(jié),就是這個(gè)指針的大小
NSObject *obj = [[NSObject alloc] init];
//對象的成員變量占用的大小,j就是這個(gè)對象至少需要多大內(nèi)存
NSLog(@"%zd",class_getInstanceSize([NSObject class]));
2019-12-04 20:44:25.296641+0800 test1[29566:289914] 8
那為什么給obj對象分配了16個(gè)字節(jié)呢,實(shí)際上查看OC的源碼會發(fā)現(xiàn),alloc給對象分配空間的時(shí)候,AllocWithZone
的實(shí)現(xiàn)就明白了了
到這里就很明了了,所以一個(gè)OC對象至少占用16個(gè)字節(jié),實(shí)際上alignedInstanceSize()返回的是8個(gè)字節(jié),小于16,默認(rèn)返回最小16
如果創(chuàng)建一個(gè)student的對象,他的本質(zhì)又是什么呢,
帶有一個(gè)age屬性的student對象
@interface students : NSObject{
int _age;
}
編譯成C++可以看到
struct students_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
};
還是一個(gè)結(jié)構(gòu)體,student繼承NSObject,第一個(gè)就是NSObject的isa指針,父類的成員變量放到前面,自己的放到最后,那么student占用多少個(gè)字節(jié),age占用4個(gè)字節(jié),isa占用8個(gè),應(yīng)該是12個(gè),但是運(yùn)行發(fā)現(xiàn),其實(shí)是占用16個(gè),原因是內(nèi)存對齊的規(guī)則:結(jié)構(gòu)體的最終大小必須是最大成員的倍數(shù),isa占用8個(gè)字節(jié),所以增加了一個(gè)age屬性,就占用8*2=16字節(jié),而不是8+4=12字節(jié)了
students *stu = [[students alloc] init];
//對象的成員變量占用的大小,j就是這個(gè)對象至少需要多大內(nèi)存
NSLog(@"%zd",class_getInstanceSize([students class]));
//分配給對象的大小
NSLog(@"%zd",malloc_size((__bridge const void *)stu));
2019-12-04 21:21:45.602333+0800 test1[29811:309407] 16
2019-12-04 21:21:45.602937+0800 test1[29811:309407] 16
繼續(xù)給student增加屬性得到驗(yàn)證,兩個(gè)屬性同樣還是占用16個(gè)字節(jié),說明一個(gè)屬性時(shí)分配的16個(gè)字節(jié)有4個(gè)是空的
繼續(xù)給對象增加3屬性,發(fā)現(xiàn)
對象占用24個(gè)字節(jié),為什么不是分配24個(gè)字節(jié)而是32個(gè)呢,根據(jù)內(nèi)存對齊,結(jié)構(gòu)體最大的是8,分配24個(gè)沒問題呀,看明杰老師讀源碼發(fā)現(xiàn),OC對象的最小大小是16字節(jié),其實(shí)也是根據(jù)內(nèi)存對齊,OC創(chuàng)建的對象永遠(yuǎn)都是16的倍數(shù)
總結(jié)
一個(gè)NSObject對象占用多少個(gè)內(nèi)存?
系統(tǒng)分配了16個(gè)字節(jié)給NSObject對象,(可以通過malloc_size函數(shù)獲得)
但是NSObject對象內(nèi)部只使用了8個(gè)字節(jié)的空間(64位環(huán)境下,可以通過class_getInstanceSize函數(shù)獲得)