我们先来看两个结构体:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>
struct HKStruct1 {
double a; // 8
char b; // 1
int c; // 4
short d; // 2
}struct1;
struct HKStruct2 {
double a; //8
int b; //4
char c; //1
short d; //2
}struct2;
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"%lu-%lu",sizeof(struct1),sizeof(struct2));
}
return 0;
}
在
arm64
架构下,int
占用4个字节,char
占用1个字节,double
8个字节,short
2个字节,那么结构体struct1
和struct2
应该占用的大小是15个字节,即大小为15。但是我们调用函数sizeof
后的结果却为24-16(如下图),这就是系统内存对齐后的结果。内存对齐的概念
就是编译器为程序中的每个“数据单元”安排在适当的位置上,如果不对齐,那么处理器访问这片内存就需要两次访问,而访问对齐后的内存只需要一次。即空间换时间。
内存对齐的原则
1、数据成员对⻬规则:结构(struct
)(或联合(union
))的数据成员,第⼀个数据成员放在offset
为0的地⽅,以后每个数据成员存储的起始位置要从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,结构体等)的整数倍开始(⽐如int
为4字节,则要从4的整数倍地址开始存储。
2、结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a
⾥存有struct b
,b
⾥有char,int ,double
等元素,那b
应该从8的整数倍开始存储)。
3、结构体的总⼤⼩,也就是sizeof
的结果,必须是其内部最⼤成员的整数倍,不⾜的要补⻬。
4、每个特定平台上的[编译器]都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过[预编译]命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
接下来我们详细解析,为什么两个结构体的内存大小不一致:
结构体1
struct HKStruct1 {
double a; // 长度8 < 16 按8对齐;起始offset=0 0%4=0;存放位置区间[0,7]
char b; // char型,长度1 < 8 按1对齐;起始offset=8 8%1=0;存放位置区间[4]
int c; // 4 int型,长度4 < 16 按4对齐;起始offset=9 `9%4!=0`,12%4=0;存放位置区间[12,15]
short d; // 2 char型,长度2 < 16 按2对齐;起始offset=16 16%2=0;存放位置区间[16,17]
}struct1;
-
double
类型,长度8个字节,起始位置offset
= 0,0%4 = 0;存放位置区间[0,7] -
char
类型,长度1个字节,起始位置offset
= 8 ,8%1 = 0,存放位置区间[8] -
int
类型,长度4个字节,起始位置offset
= 9,9%4 != 0,因为不能整除,所以往后移,到12的位置,即12%4 = 0;存放位置区间[12,15] -
short
类型,长度2个字节,起始位置offset
= 16,16%2 = 0,存放位置区间[16,17] - 所以结构体的大小为24,即8的整数倍。
结构体2
struct HKStruct2 {
double a; //8
int b; //4
char c; //1
short d; //2
}struct2;
-
double
类型,长度8个字节,起始位置offset
= 0,0%4 = 0;存放位置区间[0,7] -
int
类型,长度4个字节,起始位置offset
= 8 ,8%4 = 0,存放位置区间[8,11] -
char
类型,长度1个字节,起始位置offset
= 12,12%4 = 0,存放位置区间[12,13] -
short
类型,长度2个字节,起始位置offset
= 14,14%2 = 0,存放位置区间[14,15] - 所以结构体的大小为16,即8的整数倍。
实例分析
结构体嵌套结构体
//1、结构体嵌套结构体
struct Mystruct3{
double b; //8
int c; //4
short d; //2
char a; //1
struct HKStruct2 str;//16
}struct3;
实例2结构体嵌套结构体
struct Mystruct4{
short d; //2字节
char a; //1字节
struct Test {
double x;
}test;
}struct4;
打印的结果和我们上面分析的结果相同。