美文网首页
iOS - 内存对齐

iOS - 内存对齐

作者: malgee | 来源:发表于2020-09-10 11:19 被阅读0次

    1、内存对齐是什么?

    在计算机中,内存大小的基本单位是字节,理论上来讲,可以从任意地址访问某种基本数据类型。

    但是实际上,计算机并非按照字节大小读写内存,而是一定倍数(8、16倍)的字节块来读写内存。因此,编译器会对基本数据类型的合法地址作出一些限制,即它的地址必须是一定倍数(8、16倍)。那么就要求各种数据类型按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

    2、内存对齐的原则

    内存对齐应该是编译器的管辖范围,编译器为程序中的每个数据单元安排在适当的位置上,方便计算机快速高效的进行读取数据。

    每个平台的编译器都有自己的对齐系数和相应的对齐规则。在iOS中的64位架构下,对齐系数就是8个字节。

    2.1 数据成员对齐

    结构体(struct)或联合体(union)中的成员变量中,首个成员变量放在偏移量为0的位置上,后面的成员变量的对齐偏移量是取指定对齐系数和本身该成员变量所占用大小中的较小值,即min(对齐系数,成员变量的内存大小 )

    2.2 数据整体对齐

    结构体(struct)或联合体(union)的数据成员中的成员变量完成自身的对齐之后,整个 结构体(struct)或联合体(union)也需要进行字节对齐处理,一般为min(对齐系数,最大成员变量的内存大小 )的整数倍。

    结合上述原则1、2,可以推断出下面的常用原则,以结构体为例:

    • 结构体变量的首地址是其最长基本类型成员的整数倍;
    • 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如不满足,对前一个成员填充字节以满足;
    • 结构体嵌套结构体的内存大小必须是结构体中最大成员内存大小的整数倍,不足的需要补齐。

    结合上述分析, 可以总结出内存对齐原则:

    • 【1】 数据成员的对齐规则可以理解为min(m, n) 的公式, 其中m表示当前成员的开始位置, n表示当前成员所需要的占用字节个数。如果满足条件 m 整除 n (即 m % n == 0), nm 位置开始存储, 反之继续检查 m+1 能否整除 n, 直到可以整除, 从而就确定了当前成员的开始位置。

    • 【2】数据成员为结构体:当结构体嵌套了结构体时,作为数据成员的结构体的自身长度作为外部结构体的最大成员的内存大小,比如结构体a嵌套结构体b,b中有char、int、double等,则b的自身长度为8

    • 【3】结构体的内存大小必须是结构体中最大成员内存大小的整数倍,不足的需要补齐。

    下表示各数据类型在iOS中占用的内存大小

    image.jpeg

    结构体内存对齐

    接下来我们分析下结构体的内存分布

    struct MGStruct1 {
        //           占字节数     起始位置            占的位置
        double a;   // 8         0                 (0 1 2 3 4 5 6 7)
        char b;     // 1         8                 (8)
        int c;      // 4         9         9 10 11 (12 13 14 15)
        short d;    // 2         16                (16 17)
    }struct1;
    
    // 结构体内部需要的内存大小为: 18
    // 最大属性占用内存 : 8
    // 结构体整数倍: 24
    
    struct MGStruct2 {
        //           占字节数     起始位置            占的位置
        double a;   // 8         0                 (0 1 2 3 4 5 6 7)
        int c;      // 4         8                 (8 9 10 11)
        char b;     // 1         12                (12)
        short d;    // 2         13                (14 15)
    }struct2;
    
    // 结构体内部需要的内存大小为: 16
    // 最大属性占用内存 : 8
    // 结构体整数倍: 16
    
    struct MGStruct3 {
        //           占字节数     起始位置            占的位置
        int c;      // 4         0                 (0 1 2 3)
        double a;   // 8         4         4 5 6 7 (8 9 10 11 12 13 14 15)
        char b;     // 1         16                (16)
        short d;    // 2         17             17 (18 19)
    }struct3;
    
    // 结构体内部需要的内存大小为: 20
    // 最大属性占用内存 : 8
    // 结构体整数倍: 24
    

    控制台打印输出可以到处:

    24      16      24
    
    image.png

    按照前面分析的内存对齐原则可以知道内存分布情况

    image.png

    注:空白部分为补齐的内存位置

    struct1 为例做出分析内存大小过程如下:

    • 变量adouble类型, 占用8字节 ,从 0 开始, 占用位置 0, 1, 2, 3, 4, 5, 6, 7
    • 变量bchar 类型, 占用1字节,从8位置开始, 占用位置 8
    • 变量cint 类型, 占用4字节,按理说应该从 9 位置开始,但是按照内存对齐原则9不能被4整除,需要向后偏移,知道找到能整除4的位置,位置12可整除4, 所以占用位置 12, 13 14 15
    • 变量dshort类型,占用2字节,从16位置开始 ,占用位置16, 17

    按照内存对齐原则分析得出:struct1最大变量字节数为8,分析完成4个属性(a, b, c,d)需要18字节内存, 而实际的内存大小必须是 8 的整数倍,18向上取整到24,主要是因为24是8的整数倍,所以sizeof(struct1) 的结果是 24

    结构体嵌套结构体

    定义一个嵌套结构体 struct2_1_1

    struct Struct2_1_1 {
        //           占字节数     起始位置            占的位置
        int c;      // 4         0                 (0 1 2 3)
        double a;   // 8         4                 (8 9 10 11 12 13 14 15)
        struct Struct3 struct3;   // 8             (16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39)  ==> struct3 内存大小 24
        char b;     // 1         40                (40)
        short d;    // 2         41                (42 43)
    }struct2_1_1;  // => 48
    

    分析过程:

    • 变量cint 类型 , 占用4字节, 从0开始, 占用位置 0 1 2 3
    • 变量adouble类型, 占用8字节,从4开始,占用位置 8 9 10 11 12 13 14 15
    • struct3结构体,上面分析占用24字节,最大属性内存占8字节(struct3 中的 a 是double类型,占8字节 ), 依据内存对齐原则,当前成员的开始位置应该能整除8,所以从 16开始,占用位置16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
    • 变量bchar类型, 占用1字节,从40开始, 占用位置40
    • 变量dshort类型, 占用2字节,从41开始, 占用位置42 43

    因此struct2_1_1需要的内存大小44字节, 而 struct2_1_1中的最大属性占用8字节, 根据内存对齐原则可以 得出 结构体的内存大小必须是8的整数倍,即sizeof(struct2_1_1) = 48

    内存分析图:

    image.png

    注:空白部分为补齐的内存位置

    更多结构体分析可以查看demo

    相关文章

      网友评论

          本文标题:iOS - 内存对齐

          本文链接:https://www.haomeiwen.com/subject/ejzuektx.html