iOS 底层探究二 - 结构体内存对齐

218 阅读1分钟

一、知识补充-内存对齐算法

8字节对齐

字节数(字节)所开辟字节大小(字节)
0~88
9~1616
17~2424
...8*n

8字节对齐算法公式: (x + 7)& ~7
例如:( 12 + 7 )& ~7 = 16 另外一种算法: x >> 3 << 3

同理16字节对齐算法 : (x+15) &~15

从objc源码中,我们可以得知,在iOS中时才用16字节对齐

    inline size_t instanceSize(size_t extraBytes) const {
        if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
            return cache.fastInstanceSize(extraBytes);
        }

        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }
    
       // Class's ivar size rounded up to a pointer-size boundary.
    uint32_t alignedInstanceSize() const {
        return word_align(unalignedInstanceSize());
    }
    
    static inline size_t word_align(size_t x) {
    return (x + WORD_MASK) & ~WORD_MASK;
}
#   define WORD_MASK 7UL

二、结构体内存对齐

比较两个结构体的内存大小

struct LGStruct1 {
    char b;     //   1       
    int c;        // 2  3 [ 4 5 6 7 ]   
    double a;     // 8 9 10 11 12 13 14 15 
    short d;      // 16 17    24
}struct1;

struct LGStruct2 {
    double a;  //        
    int b;            
    char c;            
    short d;          
}struct2;

根据内存对齐原则

struct LGStruct1 {
    char b;     //   1       
    int c;        // 2  3 [ 4 5 6 7 ]   
    double a;     // 8 9 10 11 12 13 14 15 
    short d;      // 16 17    24
}struct1;

struct LGStruct2 {
    double a;  //  0 1 2 3 4 5 6 7      
    int b;     //  8       
    char c;    //  9  10  11 [ 12 ]        
    short d;   //  13 [ 14 15 ]      16      
}struct2;

所以得到LGStruct1的内存大小为 24,LGStruct2的内存大小为16

再来看一个:

struct LGStruct3 {
   double a; // 0 - 7    8字节*1
   int b;    // 8 - 11
   char c;   // 12。     8字节*2
   struct LGStruct1 str1;  // 24字节*1
   short d;  // 40 - 41
   int e;    // 44 -47   8字节*3
   struct LGStruct2 str2; // 16字节*1
}struct3;

所以LGStruct3 是64字节

验证

NSLog(@"%lu-%lu-%lu",**sizeof**(struct1),**sizeof**(struct2),**sizeof**(struct3));
// 24-16-64

内存对齐原则

1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第 ⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要 从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组, 结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存 储。 min(当前开始的位置m n) m = 9 n = 4 9 10 11 12

2:结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从 其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a⾥存有struct b,b ⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.)

3:收尾⼯作:结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤ 成员的整数倍.不⾜的要补⻬。