对于大多数研究底层的程序员,对内存对其应该都不陌生,今天小生来献丑一波。
内存对齐的定义
内存对齐 应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。
对于大部分研究过底层的程序员来说,“内存对齐”对他们来说都应该是“透明的”。
为什么要内存对齐
由于本人文采不好,借用下百度百科的解释。
- 1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
- 2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
内存对齐的规则
(很长,说实话,我也懒得看下去。。没关系,后面我会举例解释)
- 1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第 一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要 从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组, 结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存 储。 min(当前开始的位置mn) m=9 n=4 那么 9 10 11 12 、 就要从12开始存储
- 2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从 其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b 里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
- 3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大 成员的整数倍.不足的要补⻬
各类型所占字节
我也知道大家这个表都知道,但是不把图啪上感觉没有仪式感
举例说明内存对齐
上面罗里吧嗦的终于结束了。只看理论啥收获都没有感觉,还是不让代码验证解释比较痛快。
我会通过结构体来说明
- 例1:
注: {}代表解释说明 。
struct XGStruct1 {
double a; // 8{所占字节数} (0{开始位置}-7{结束位置}){所占字节位置}
char b; // 1{所占字节数} [8{开始位置} 1{所占字节数}] (8){存储字节位置}
int c; // 4{所占字节数} [9{开始位置} 4{所占字节数}] 9 10 11 (12 13 14 15){存储字节位置}
short d; // 2{所占字节数} [16{开始位置} 2{所占字节数}] (16 17){存储字节位置}
}struct1;
解释说明:
内存对齐规则1:开始位置必须是所占字节数的整数倍,才能开始存。
(举例:char b,由于开始位置是所占字节数的整数倍可以直接存,int c ,开始位置是从9,并不是4的整数倍,所以从12开始存)
存储大小是:18{0-17}
由于结构体中存在double为最大字节数:8
(内存对齐规则3:所占内存必须是最大字节数的整数倍。所以必须是8的整数倍。18-->24)
所以所占内存大小是24.
输出log确认下:
NSLog(@"%lu",sizeof(struct1));
log输出:24
- 例2:
这个应该就比较形象了。
struct XGStruct2 {
int b; //4{所占字节数} [0{开始位置} 4{所占字节数}],(0 1 2 3){存储字节位置}
char c; //1{所占字节数} [4{开始位置} 1{所占字节数}], (4){存储字节位置}
short d; //2{所占字节数} [5{开始位置} 2{所占字节数}], 5 (6 7){存储字节位置}
short e; //2{所占字节数} [8{开始位置} 2{所占字节数}], (8 9){存储字节位置}
}struct2;
解释说明:
1、内存所占大小是 10(0-9)
2、内存中最大的字节是int(4),所以是4的整数倍。
理论结果:12
验证:
NSLog(@"%lu",sizeof(struct2));
输出:
12
内存对齐规则的扩展
以上2个例子应该可以说明内存对其规则了。我相信大家也都懂了。那么,咱们来一波进阶:结构体嵌套结构体。
继续用上面两个例子,然后加以改正:
struct XGStruct1 {
double a;
char b;
int c;
short d;
}struct1;
//已证
struct XGStruct2 {
int b;
char c;
short d;
short e;
}struct2;
//已证
我们把XGStruct2 改变下,加入XGStruct1,变成XGStruct3:
struct XGStruct3 {
int b;
char c;
short d;
short e;
struct XGStruct1 xgs;
}struct3;
大家可以先想想下,所占内存大小?
解释了啊:
首先。我们先通过规则,大概猜一下,会是什么样子的。。
然后我要开始验证了啊。。
先换一种好说明的写法
struct XGStruct3 {
int b; //4{所占字节数} [0{开始位置} 4{所占字节数}],(0 1 2 3){存储字节位置}
char c; //1{所占字节数} [4{开始位置} 1{所占字节数}], (4){存储字节位置}
short d; //2{所占字节数} [5{开始位置} 2{所占字节数}], 5 (6 7){存储字节位置}
short e; //2{所占字节数} [8{开始位置} 2{所占字节数}], (8 9){存储字节位置}
struct XGStruct4 {
double a;// [10 8] 10 11 12 13 14 15 (16 17 18 19 20 21 22 23)
int b; // [24 4] (24 25 26 27)
char c; // [28 1] (28)
short d; // [29 2] 29 (30 31)
}xgs;
}struct3;
所占大小是32 (0-31)
里面最大类型是double(8),又是8的倍数,那岂不是结果是32,
验证一波:
NSLog(@"%lu",sizeof(struct3));
输出:
32
还真是!!!!!
大家可以通过多写点例子来验证。。看来内存对齐的规则还是挺好用的。。