iOS底层原理探索 -- 结构体内存对齐研究

内存对齐的概念

内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。

内存对齐的规则

1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储。 

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

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



探究开始

先创建一个结构体

    structFQStructOne {

         char       a;        //1字节 

        double   b;        //8字节 

        int           c;          //4字节 

        short      d;        //2字节 

    } FQStruct1;

如果没有内存对齐,那么实际内存应该是1+8+4+2 = 15

那么实际呢

  NSLog(@"FQStruct1:%lu", sizeof(FQStruct1));

根据打印结果24,所以必然是有经过重排

那按照重拍规则,我们来计算一下结构体目前的存储位置

 structFQStructOne {

char       a;        //1字节    [ 0 ]       规则1

 double   b;        //8字节  [8-15]   规则1  

 int           c;          //4字节 [16-19] 规则1

 short      d;        //2字节  [20-21] 规则1

    } FQStruct1;

一共22个字节 根据规则3 ,补为最大成员8的倍数 24

计算结果与实际一致

猜测  - 结构体的成员位置影响结构体大小

从第一个结构体可以看出 地址1-7其实是空置的,但由于b的字节交大,受规则2影响,只能从其整数倍的位置开始,所以我们改变结构体成员的位置后是否可以改变其结构体大小?

由此,我们创建结构体2

    structFQStructTwo {

        double b;      //8字节  [0-7]  规则1

        int         c;       //4字节 [8-11]规则1

        char      a;      //1字节  [12]      规则1

        short    d;      //2字节 [14-15] 规则1

    } FQStruct2;


总大小16,符合规则3,所以最终大小16   运行打印 16

可见 结构体大小确实可以通过改变成员的先后顺序来影响



继续探究 结构体嵌套结构体时结构体的内存对齐

    structFQStructThree {

        double  b;        //8字节 [0-7]       规则1

        char       a;        //1字节 [8]           规则1

        short     d;        //2字节 [10-11]  规则1

        int          c;         //4字节 [12-15]  规则1

        struct FQStructTwo e;//16字节 [16-31] 规则2

    } FQStruct3;

同时,我们展开FQStructTwo计算

    structFQStructTwo {

        double   b;       //8字节  [16-23]  规则1

        int          c;         //4字节 [24-27]规则1

        char       a;         //1字节  [28]      规则1

        short      d;         //2字节 [30-31] 规则1

    } e;

与打印出的内存大小32一致。

推测可以按照满足要求的起始点然后直接加上结构体的大小,然后再做最后规则3的补齐运算

问题  

1.推测是否成立。 

2.规则3中提到的必须是其内部最大成员的整数倍, 这个最大成员是结构体还是结构体和其嵌套的结构体内部的最大成员

    structFQStructFour {

        double     b;        //8字节 [0-7]  规则1

        char          a;          //1字节 [8]    规则1

        struct FQStructTwo e;//16字节 [16-31] 规则2

        short        d;        //2字节 [32-33]  规则1

        int            c;          //4字节 [36-39]  规则1

    } FQStruct4;

此时,按照我们计算,结构体若以double对象为最大元素,那么补齐应当为40,若以结构体内的结构体e为最大元素,则结果为48。

打印 值为40

所以可以证明问题2中内部最大成员并非为其中的结构体变量。同时符合按照满足要求的起始点然后直接加上结构体的大小,然后再做最后规则3的补齐运算 的推断。

    structFQStructFour {

        char             a;          //1字节 [0]    规则1

        struct FQStructThree e;//16字节 [8-23] 规则2

        double        b;        //8字节 [24-31]  规则1

        short           d;        //2字节 [32-33]  规则1

        int                c;          //4字节 [36-39]  规则1

    } FQStruct4;

log输出为40,符合验证结果。


ps.这样写博客有点累,回头还是研究下MarkDomn

你可能感兴趣的:(iOS底层原理探索 -- 结构体内存对齐研究)