iOS 底層探究二:內存對齊1

這是我參與8月更文挑戰的第2天,活動詳情查看:8月更文挑戰

內存對齊的原則

1.數據成員對齊規則

結構體(struct)或者聯合體(union)的數據成員,第一個數據成員放在offset爲0的地方,之後每一個數據成員存儲的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員,好比說是數組,結構體等)的整數倍開始(好比int爲4字節,則要從4的整數倍地址開始存儲)。express

2.結構體做爲成員

若是一個結構裏有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍地址開始存儲。(struct a裏存有struct b,b裏有char,int,double等元素,那b應該從8的整數倍開始存儲)。數組

3.首位工做

結構體的總大小,也就是sizeof的結果,必須是其內部最大成員的整數倍。不足的要補齊。markdown

基本數據類型的內存大小

C OC 32位 64位
bool BOOL(64位) 1 1
signed char (__signed char)int8_t、BOOL(32位) 1 1
unsigned char Boolean 1 1
short int16_t 2 2
unsigned short unichar 2 2
int 、int32_t NSInteger(32位)、boolean_t(32位) 4 4
unsigned int boolean_t(64位)、NSUInteger(32位) 4 4
long NSInteger(64位) 4 8
unsigned long NSUInteger(64位) 4 8
long long int64_t 8 8
float CGFloat(32位) 4 4
double CGFloat(64位) 8 8

如何獲取內存大小

1. sizeof(expression-or-type)

sizeof()C/C++中的關鍵字,它是一個運算符,不是函數。做用是取得一個對象(數據類型或者數據對象)的長度(即佔用內存的大小,以byte爲單位,返回size_t)。基本數據類型(intdouble等)的大小與系統相關。結構體涉及字節對齊。函數

示例:post

struct Stu {

        char c;
        int i;
        double d;
    };

    void test() {

        //基本數據類型
        int age = 18;
        size_t sizeAge1 = sizeof(age);
        size_t sizeAge2 = sizeof age;
        size_t sizeAge3 = sizeof(int);
        NSLog(@"age size: %zu, %zu, %zu",sizeAge1,sizeAge2,sizeAge3);

        //結構體
        struct Stu s;
        s.c = 'c';
        s.i = 18;
        s.d = 180.0;

        size_t sizeS1 = sizeof(s);
        size_t sizeS2 = sizeof s;
        size_t sizeS3 = sizeof(struct Stu);
        NSLog(@"s size: %zu, %zu, %zu",sizeS1,sizeS2,sizeS3);

        //指針
        NSObject *obj = [NSObject alloc];
        size_t sizeObj1 = sizeof(obj);
        size_t sizeObj2 = sizeof obj;
        size_t sizeObj3 = sizeof(NSObject *);
        NSLog(@"obj size: %zu, %zu, %zu",sizeObj1,sizeObj2,sizeObj3);
    }

複製代碼

輸出:spa

age size: 4, 4, 4
s size: 16, 16, 16
obj size: 8, 8, 8
複製代碼
  • 經過類型和實例均可以獲取內存大小,這也說明開闢的內存大小在類型肯定後就已經肯定了。
  • sizeof是運算符不是函數。3種語法形式均可以,須要注意的是經過類型獲取的方式必須在()中。

2. class_getInstanceSize

這個函數是rutime提供的獲取類的實例鎖佔用的內存大小。大小至於成員變量有關。獲取的是實際佔用的空間(8字節對齊)。指針

3. malloc_size

malloc_size就是alloc中實際開闢的空間。code

案例份分析

1.有以下結構體Struct1Struct2分別佔用多大內存?

struct Struct1 {
    double a; // [0,7]
    char b;     // [8]
    int c;        // 根據第一準則要從4的倍數開始,因此[12,13,14,15]。跳過9,10,11
    short d;  //[16,17]
}struct1;
//根據第三準則總大小要是8的倍數,那就要分配24字節。

struct Struct2 {
    double a; //[0,7]
    int b;        //[8,11]
    char c;     //[12]
    short d;   //根據準則1跳過13,從14開始 [14,15]
}struct2;
//這裏0~15大小原本就爲16了,因此不須要補齊了。
複製代碼

驗證:orm

NSLog(@"struct1 size :%zu\nstruct2 size:%zu",sizeof(struct1),sizeof(struct2));
複製代碼

輸出:對象

struct1 size :24
struct2 size:16
複製代碼
  • 結構體中數據類型順序不一致佔用的內存大小可能不一致。
  • 大小計算從0開始,Struct2並無進行第三原則補齊。

2. 增長一個Struct3中有結構體嵌套,那麼佔用大小是多少?

struct Struct3 {
    double a;                  //[0,7]
    int b;                         //[8,11]
    char c;                     //[12]
    short d;                   //跳過13 [14,15]
    int e;                        // [16,19]
    struct Struct1 str; //根據準則2,Struct1最大元素爲`double`類型,因此從24開始。根據`Struct1`分配的時候24個字節,因此str爲[24,47]
}struct3;
//因此Struct3佔用內存大小爲48字節。
複製代碼

驗證:

NSLog(@"struct3 size :%zu",sizeof(struct3));

struct3 size :48
複製代碼

在這裏有個疑問,準則3是先做用在Struct1再做用Struct3仍是最後直接做用在Struct3?不妨驗證一下:

struct Struct4 {
    struct Struct1 str;
    char c;
}struct4;
複製代碼

Struct1自己佔用18字節,補齊後佔用24字節。若是Struct4最終佔用32字節那麼就是第一種狀況,張永24 字節則是第二種狀況。

NSLog(@"struct4 size :%zu",sizeof(struct4));
struct4 size :32
複製代碼

這也就驗證了猜測,結構體嵌套從內部開始補齊。這也符合常理。

3. 修改結構體以下:

struct S1 {
    int a; // 4  [0,3]
    char b;// 1  [4]
    short c; // 2 [6,7]
}; // 0~7 8字節

struct S2 {
    double a; // 8 [0,7]
    char b;   // 1 [8]
    struct S1 s1; // 8  [12,19]  按s1自身中存的最大a的4字節的倍數對齊
    bool c; // 1 [20]
};
//0~20一共21個字節,按最大的8字節對齊。應該24字節。
複製代碼
struct S2  s2;
NSLog(@"size :%zu",sizeof(s2));
複製代碼

這個時候s2大小爲多少?

分析:

  • S1:

    • int a4個字節,從[0~3]
    • char b1個字節,[4]
    • short c2個字節,須要以2字節對齊,因此跳過5 [6~7]
    • S1總體從0~7不須要補齊。佔8字節。
  • S2:

    • double a8字節,[0~7]
    • char b1字節,[8]
    • struct S1 s18字節。因爲S1內部最大元素爲int a因此須要4倍對齊,因此[12~19]
    • bool c1字節,[20]
    • S2總體從0~21一共21字節,須要按S2中最大元素double a補齊。因此應該是24字節。

輸出:

size :24
複製代碼
相關文章
相關標籤/搜索