iOS底層原理總結--OC物件的本質(二)

小李小李一路有你發表於2018-12-20

iOS底層原理總結--OC物件的本質(一) - 掘金

iOS底層原理總結--OC物件的本質(二) - 掘金

iOS底層原理總結--OC物件的分類:instance、class、meta-calss物件的isa和superclass - 掘金

iOS底層原理總結-- KVO/KVC的本質 - 掘金

iOS底層原理總結 -- 利用Runtime原始碼 分析Category的底層實現

...

思考: 如果我的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物件的記憶體地址:

OC_%E6%89%93%E5%8D%B0%E5%86%85%E5%AD%98%E5%9C%B0%E5%9D%80log.png
xcode控制檯常用指令:Xcode偵錯程式LLDB - 掘金

這裡我們的記憶體地址為:<Student: 0x600002746b60>

OC_2_%E6%89%93%E5%BC%80viewMemory.png
然後選擇:Debug --> Degug Workflow --> View Memory

OC_2_ViewMemory_01.png
在下方的位置輸入我們剛剛得到的記憶體地址後就可以了,stu的記憶體結構如上圖所示

OC_2_ViewMemory_02.png
直到紅線的位置都是stu所開闢的儲存空間,直到紅色數線後才有了新的值, 在之前都是00值而且在記憶體中記憶體是連續的, 所以我們可以認為,直到紅色豎線位置之前都是stu所分配的儲存空間

OC_2_ViewMemory_03.png
如上圖所示

  • 綠色區域:前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個位元組。


  • 文章總結自MJ老師底層視訊。

相關文章