一、什么是内存对齐?
内存对齐(Memory alignment)
是一种在计算机内存中排列数据(表现为变量的地址)、访问数据(表现为CPU读取数据)的一种方式。
它包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐。
二、为什么要内存对齐?
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问,而对齐的内存访问仅需一次访问,每次内存存取都会产生一个固定的开销,减少内存存取次数将提升程序的性能。
三、内存对齐的规则
1、数据成员对齐规则
结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack
指定的数值和这个数据成员自身长度中,比较小的那个进行。
struct Struct2 {
short b; // 2 从初始位置开始排 占0~1位
char c; // 1 从1的倍数开始排 占第2位
double a; // 8 从8的倍数开始排 占8~15位
int d; // 4 从4的倍数开始排 占16~19位
} myStruct2;
因为我们这边是以 8字节 对齐,所以会自动补齐,应该是8的倍数 24位。
2、结构(或联合)的整体对齐规则
在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack
指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
struct Struct3 {
double b; // 8 从初始位置开始排 占0~7位
int c; // 4 从4的倍数开始排 占8~11位
char a; // 1 从1的倍数开始排 占第12位
short d; // 2 从2的倍数开始排 占14~15位
struct Struct4 {
double e; // 8 从8的倍数开始排 占16~23位
char h; // 1 从1的倍数开始排 占第24位
int j; // 4 从4的倍数开始排 占28~31位
} myStruct4;
} myStruct3;
整体对齐系数 = min(max(myStruct4),8)
= 8
, 即内存大小由31补齐到8的倍数 32 。
3、结构体作为成员
如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。
struct Struct3 {
double b; // 8 从初始位置开始排 占0~7位
int c; // 4 从4的倍数开始排 占8~11位
char a; // 1 从1的倍数开始排 占第12位
short d; // 2 从2的倍数开始排 占14~15位
struct Struct4 {
double e; // 8 从8的倍数开始排 占16~23位
char h; // 1 从1的倍数开始排 占第24位
int j; // 4 从4的倍数开始排 占28~31位
} myStruct4;
} myStruct3;
如:myStruct4
中 double 长度 8 = 8,则按8对齐,起始offset = 16,存储位置区间为 16~23。
补充说明:
1、在这,你可能会疑惑#pragma pack
是什么东西呢?
#pragma pack 其实就是指定内存对齐系数,如1,2,4,8,16。Xcode默认的对齐系数是8。
2、结构体的变量的首地址是其最长基本数据成员的整数倍
3、结构体每个成员的相对于结构体首地址的偏移量是其数据长度的整数倍。如果有需要,编译器会在成员之间填充字节。
网友评论