底层原理-02-结构体内存分析

661 阅读3分钟

首先可以看一张基本数据类型内存图

截屏2021-06-08 下午5.40.44.png 基本上一样只有long类型在64位处理器是8个字节

1.下面结构体所占内存大小一样吗?

首先我们看下下面的代码

struct struct1 {
    double a;
    int b;
    bool c;
    char d;
};
struct struct2 {
    bool c;
    double a;
    int b;
    char d;
};

int main(int argc, char * argv[]) {

    struct struct1 a;
    struct struct2 b;
    NSLog(@"a:%ld,b:%ld",sizeof(a),sizeof(b));
    return 1;
}

2个属性完全一样的结构体,但是打印的大小不一样打印发现 结构体内存对齐方式探究[14738:1065329] a:16,b:24 为什么呢?

2.结构体对齐规范原则

2.1数据成员对⻬规则

结构体struct或联合体union的数据成员第一个成员从offse为0开始,根据自己所规定的内存大小往后数多少位(如果第一个成员是结构体或者联合体就已该成员中最大内存字节往后数计算内存)后面的每个成员的存储起始位置为该成员或成员的子成员大小的整数倍数开始(比如int 是4字节,则要从4的整数倍地址开始存储。 min(当前开始的位置mn)m=9n=4 9 10 11 12

2.2结构体作为成员

如果一个结构体有子结构体,那么该子结构体第一个内部元素存储起始位置要从该子结构体中最大的元素大小的倍数开始存储(struct a 有struct b b中有元素bool sub1,int sub2,double sub3。那么起始位置就应该是8的倍数)

2.3结构体收尾补齐

最后结构体的大小,sizeof()的大小必须是结构体中最大元素的大小的倍数,,不足补齐,向上取倍数。

分析可知

struct struct1 {
    double a; // -> 8 byte [0 8] (0,1,2,3,4,5,6,7)
    int b;   //-> 4 byte [8 4] (8,9,10,11)
    bool c;  //-> 1 byte [12 1] (12)
    char d;  //-> 1 byte [13 1] (13) 向上补齐8的倍数->16
};
struct struct2 {
    bool c; // ->1 byte [0 1] (0)
    double a; //->8 byte [8 8] (8,9,10,11,12,13,14,15) 
    int b;// ->4 byte [16 4] (16,17,18,19)
    char d;// ->4 byte [20 1] (20) 向上补齐8的倍数 ->24
};
//补充说明
struct struct3{
    bool c; //[0-1]
    double a;//[8-8]
    int b; //[16-4]
    struct subStr{
          BOOL c;//  [24 1] ->子结构体以该结构体中元素最大字节的倍数(8)为起始位置-> (20->24)
          double a;// [32 -8]
          char b;// [40 -1]
      } f;//结构体收尾补齐原则,所以应该41->48
    char d;// [48 -1] 结构体收尾补齐原则 49补齐8的倍数 56

};

3.为什么要内存对齐?

我们知道计算机存储数据一般以字节(byte)形式进行存储,读取的时候却不是以一个字节方式进行读取,而是根据数据类型和处理器进行读取,一般以,1字节,2字节,4字节,8字节,16字节,甚至32字节来存取内存,我们将上述这些存取单位称为 内存存取粒度

举个列子

内存没有对齐的情况下,读取 int类型数据

截屏2021-06-08 下午5.28.00.png 第一次读取长度为4个字节内存,没有读取完,只读了一半

截屏2021-06-08 下午5.29.05.png 由于没有读取完整的数据,要向右便宜4个单位进行读取 如上图 这个时候才读取完成,还要进行合并删除处理,很耗时间 这个时候如果内存对齐的话

截屏2021-06-08 下午5.29.43.png 只要读取一次就可以了,就拿到我们要的数据。所以内存对齐的原因是可以大大节约我们读取时间,提高效率。

总结

内存对齐是需要遵守的一套规则,通过适当增加内存大小,达到一次就能读取内存数据,以达到一点点空间换取时间,提高效率。