前言
我们知道,计算机数据是以二进制存储的,一个字节有8位,如果计算机每次读取一个字节的话,效率会非常低,并且随着cpu是64位情况下,意味着每次可以同时处理8个字节的数据。比如我们创建了一个类对象,占用22个字节,那么cpu读取了三次,还要从第三次中取出前6个字节,来构成对象,这样情况下会影响效率,因此,在64位机器上,内存默认的就是8字节对齐,每次读取8字节数据。 因此,假如我申请了一段内存占用了22个字节,那么为了遵守字节对齐原则,系统就会分配给24个字节。(8的整数倍)
那具体的数据占用内存大小是怎么计算的呢? 仅仅是简单的累加么? 比如下面
struct Struct0 {
int a; // 4
int b; // 4
int c; // 4
char d; // 1
short e; // 2
}myStruct0;
这个结构体,占用内存是 4 + 4 + 4 + 1 + 2 = 19 然后8字节对齐 分配24个吗,结果打印出来
16---
内存对齐原则
- 数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第 一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要 从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组, 结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存 储。
- 结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从 其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b 里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
- 收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大 成员的整数倍.不足的要补⻬。
是不是有点看不懂,没关系,我们还是看刚才那个结构体,按照原则,我们可以标注下他们的开始位置:
struct Struct0 {
int a; // 4 0-3
int b; // 4 4 - 7
int c; // 4 8-11
char d; // 1 12
short e; // 2 14 - 15
}myStruct0;
// 代码验证下
myStruct0.a = 1;
myStruct0.b = 2;
myStruct0.c = 3;
myStruct0.d = 4;
myStruct0.e = 5;
NSLog(@"%p--- ",&myStruct0);
拿到指针地址后
(Struct0 *) $0 = 0x0000000109ed8868
我们打开debug模式下,view memery这个菜单,把地址输进去发现输出
01 00 00 00 02 00 00 00 03 00 00 00 04 00 05 00
由于ios系统中二进制使用的是小端模式,不懂可以百度 我们发现
01 00 00 00 这个值就是a,从第0位置开始
02 00 00 00 这个值就是b,从第4位置开始
03 00 00 00 这个值就是c,从第8位置开始
04 这个值就是d,从第11位置开始
05 00 这个值就是e,从第14位置开始
所以该结构体就占用内存16个字节。
ios 开发中内存申请16字节对齐
在我们看calloc源码的时候,我们注意到它是16字节对齐,为什么要这样呢? 因为我们知道,ios中所有的对象都是继承NSObjec对象,而NSObject对象中是一个结构体指针,大小为8个字节,如果还是以8个字节对齐的话,会有可能出现内存数据出错,没有容错处理,因此采用16字节对齐。