首先我们定义了三个结构体 LGStruct1、LGStruct2 和 LGStruct3,然后通过控制台打印出三个结构体类型的内存大小。

首先我们定义了三个结构体 LGStruct1LGStruct2LGStruct3,然后通过控制台打印出三个结构体类型的内存大小。

struct LGStruct1 {
    double a;  
    char b;     
    int c;      
    short d;    
}struct1;

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

struct LGStruct3 {
    double a; 
    int b;     
    char c;     
    short d;    
    struct LGStruct1 e;
}struct3;

NSLog(@"%lu-%lu-%lu",sizeof(struct1),sizeof(struct2),sizeof(struct3));


可以看到,控制台的打印结果如下:

LGStruct1、LGStruct2 两个结构体拥有的变量数量跟类型都大同小异,到底是什么原因导致两个结构体在内存大小的表现上会有截然不同的结果?LGStruct3 的内存大小又是如何计算出来的?

基本数据类型内存大小

内存对齐的原则

  1. 数据成员对⻬规则:结构 (struct)(或联合(union)) 的数据成员,第⼀个数据成员放在 offset 为 0 的地⽅,以后每个数据成员存储的起始位置要从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,结构体等)的整数倍开始(⽐如 int 为4字节,则要从4的整数倍地址开始存储。
  2. 结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从其内部最⼤元素⼤⼩的整数倍地址开始存储。(struct a ⾥存有 struct b,b ⾥有 char、int 、double 等元素,那 b 应该从 8 的整数倍开始存储。)
  3. 收尾⼯作:结构体的总⼤⼩,也就是 sizeof 的结果,必须是其内部最⼤成员的整数倍,不⾜的要补⻬。

案例解析

了解系统对结构体内存对齐的原则后,我们回过头再看一下文章一开头的三个结构体 LGStruct1、LGStruct2 和 LGStruct3。

结构体 LGStruct1,通过内存对齐规则计算过程如下:

  • 变量 a:double 占 8 个字节,从 0 位置开始,则 0-7 存储 a
  • 变量 b:char 占 1 个字节,从 8 位置开始,此时 8 是 1 的整数倍,则 8 存储 b
  • 变量 c:int 占 4 个字节,从 9 位置开始,但是此时 9 不是 4 的整数倍,因此需要往后继续寻找,找到最接近的能整除 4 的 12 位置,则 12-15 存储 c
  • 变量 d:short 占 2 个字节,从 16 位置开始,此时 16 是 2 的整数倍,则 16-17 存储 d
  • 收尾:LGStruct1 需要的内存大小为 18 字节,而 LGStruct1 中最⼤成员变量字节数是 8 字节,内存大小 18 字节不是内部最⼤成员的整数倍,所以必须向上补齐,补齐后的最终大小为 24 字节

结构体 LGStruct2,通过内存对齐规则计算过程如下:

  • 变量 a:double 占 8 个字节,从 0 位置开始,则 0-7 存储 a
  • 变量 b:int 占 4 个字节,从 8 位置开始,此时 8 是 4 的整数倍,则 8-11 存储 b
  • 变量 c:char 占 1 个字节,从 12 位置开始,此时 12 是 1 的整数倍,则 12 存储 c
  • 变量 d:short 占 2 个字节,从 13 位置开始,但是此时 13 不是 2 的整数倍,因此需要往后继续寻找,找到最接近的能整除 2 的 14 位置,则 14-15 存储 d
  • 收尾:LGStruct2 需要的内存大小为 16 字节,LGStruct2 中最⼤成员变量字节数是 8 字节,内存大小 16 字节刚好是内部最⼤成员的整数倍,所以最终大小为 16 字节

结构体 LGStruct3,通过内存对齐规则计算过程如下:

  • 变量 a:double 占 8 个字节,从 0 位置开始,则 0-7 存储 a
  • 变量 b:int 占 4 个字节,从 8 位置开始,此时 8 是 4 的整数倍,则 8-11 存储 b
  • 变量 c:char 占 1 个字节,从 12 位置开始,此时 12 是 1 的整数倍,则 12 存储 c
  • 变量 d:short 占 2 个字节,从 13 位置开始,但是此时 13 不是 2 的整数倍,因此需要往后继续寻找,找到最接近的能整除 2 的 14 位置,则 14-15 存储 d
  • 变量 e:内嵌的 LGStruct1 结构体,LGStruct1 内部最⼤元素的大小是 8 字节,需要从 8 的整数倍位置开始存储,存储方式同上 LGStruct1 结构体,则 16-33 存储 e
  • 收尾:LGStruct3 需要的内存大小为 34 字节,LGStruct3 中最⼤成员变量字节数是 8 字节,内存大小 34 字节不是内部最⼤成员的整数倍,所以必须向上补齐,补齐后的最终大小为 40 字节

Reference

iOS 底层探索:结构体内存对齐

本文由 简悦 SimpRead 转码, 原文地址 roadmap.isylar.com