iOS底層原理總結--OC物件的本質(二)
iOS底層原理總結–OC物件的分類:instance、class、meta-calss物件的isa和superclass - 掘金
…
思考: 如果我的Student有三個成員變數 那麼會佔用對少個位元組? (class_getInstanceSize([Student class]) 的輸出是多少? malloc_size((__bridge const void *)stu的輸出是多少? )
#import <malloc/malloc.h> #import <OBJC/runtime.h> ///> Student類 @interface Student: NSObject{ @public int _no; int _age; int _gender; } ///> 實際底層的結構體 結構 //struct Student_IMPL{ // Class isa, // int _no, // int _age; // int _gender; //} @end @implementation Student @end ///> main int main(int argc, char * argv[]) { @autoreleasepool { Student *stu = [[Student alloc]init]; stu->_no = 4; stu->_age = 5; stu->_gender = 1; NSLog(@"%zd", class_getInstanceSize([Student class])); NSLog(@"%zd", malloc_size((__bridge const void *)stu)); /**輸出結果 24 32 */ } return 0; }
- 最終的輸出結果為:
- class_getInstanceSize: 24
- malloc_size: 32
首先探究下一為什麼malloc_size的輸出為32 ?
可以使用Xcode自帶的工具去檢視 系統分配的記憶體和使用的記憶體情況。
首先我們需要拿到stu物件的記憶體地址:
xcode控制檯常用指令:Xcode偵錯程式LLDB - 掘金
這裡我們的記憶體地址為:<Student: 0x600002746b60>
然後選擇:Debug --> Degug Workflow --> View Memory
在下方的位置輸入我們剛剛得到的記憶體地址後就可以了,stu的記憶體結構如上圖所示
直到紅線的位置都是stu所開闢的儲存空間,直到紅色數線後才有了新的值, 在之前都是00值而且在記憶體中記憶體是連續的, 所以我們可以認為,直到紅色豎線位置之前都是stu所分配的儲存空間
如上圖所示
- 綠色區域:前8位就是我們上節課所說的物件的本質實質上就是結構體:然而結構體中的帶有Class isa 指標,每個物件中都會包含這個Class isa 這個指標。這個指標佔用了8個位元組。
- 藍色區域:成員變數_no:因為是Int型別所以真用了4個位元組。
- 黃色區域:成員變數_age:因為是Int型別所以真用了4個位元組。
- 灰色區域:成員變數_gender:因為是Int型別所以真用了4個位元組。
- 白色區域:所有的都是00,可以認為是已經開闢的的記憶體但是並沒有使用的區域。
由上圖分析:我們可以得出 stu實際上在記憶體中分配了32個位元組的記憶體空間 也就是 malloc_size() 所輸出的開闢記憶體空間的位元組數。
接下來探究下一為什麼class_getInstanceSize的輸出為24 ?
class_getInstanceSize 顧名思義 獲取類的例項大小
isa佔用8個 + _no:4個 + _age4個 + _gender4個
@interface Student: NSObject{
@public
Class isa; ///> 8
int _no; ///> 4
int _age; ///> 4
int _gender; ///> 4
} /// 計算相加後 為20個,
結構體存在一個記憶體對其的操作,這樣有利於CPU的訪問,
在CO中用到的記憶體對其的一條規則就是:
結構體為了保證記憶體對其 最重的真用記憶體一定是佔用最大的一個變數的倍數, 在這裡我們isa佔用了8個位元組數, 所以雖然實際上只使用了20個位元組,但是為了保證記憶體對其的規則 所以使用了24個位元組,
如果我們有4個成員變數的話:
@interface Student: NSObject{
@public
Class isa; ///> 8
int _no; ///> 4
int _age; ///> 4
int _gender; ///> 4
int _height; ///> 4
} /// 計算相加後 為24個,
我們真用的記憶體還是24,開闢依舊是32個位元組。
如果在增加一個成員變數的話:
@interface Student: NSObject{
@public
Class isa; ///> 8
int _no; ///> 4
int _age; ///> 4
int _gender; ///> 4
int _height; ///> 4
int _weight; ///> 4
} /// 計算相加後 為28個,
為了保證記憶體對其所以大小為32個位元組,開闢依舊是32個位元組。
malloc_size() 也運用了記憶體對其的 上篇文章中解釋了為什麼給類的記憶體分配了16個位元組, 由於記憶體對其的原因所以stu類分配了32個位元組。