内存对齐探索 - 初
底层探索一定会涉及到内存,前面alloc探索有讲到内存开辟的原理,那么内存是以什么方式存储排序,内存大小又是跟什么相关呢? 下面我们来进行一番验证。
对象属性展示
当对象只有一个属性变量时
得到结果如下:
当对象有两个属性变量时
得到结果如下:
我继续测试了将属性变量调整为成员变量的情况、增加方法、增加类方法等效果,这里不一一展示,可以自行验证,从我自己的验证情况得出如下结论:
sizeof是计算传进来参数的大小,因为这里是对象指针,指针对应8字节class_getInstanceSize取得的是根据结构体实际计算出来需要的对象大小malloc_size真正系统分配的对象内存大小
增加了一个NSString属性变量,计算出来的对象所需内存增加了8,这个就是一个指针的长度,那么为什么在系统分配过程,内存大小又有所不同呢?
这个就是我们的系统内存对齐原则。
内存对齐探索 - 原则
- 数据成员对齐规则:第一个数据成员从0开始,以后每个数据成员以该数据成员大小或子成员大小(数组和结构体有子成员)的整数倍开始。
- 结构体作为成员时,则结构体成员要从其内部
最大元素大小的整数倍开始存储。 - 结构体的总大小(sizeof输出结果),必须是内部最大成员的整数倍,
不足补齐。
内存对齐探索 - 数据类型对应内存大小
为什么需要补齐呢?
- 内存是以字节为单位,CUP存取数据时,是以块为单位,频繁存取未对齐的数据,会增大CUP读取工具,降低性能。而内存对齐,就是我们之前说的以空间换时间的概念。
内存是以字节为基本单位,cpu在存取数据时,是以块为单位存取,并不是以字节为单位存取。频繁存取未对齐的数据,会极大降低cpu的性能。字节对齐后,会减低cpu的存取次数,这种以空间换时间的做法目的降低cpu的开销。 cpu存取是以块为单位,存取未对齐的数据可能开始在上一个内存块,结束在另一个内存块。这样中间可能要经过复杂运算在合并在一起,降低了效率。字节对齐后,提高了cpu的访问速率。
这里举个🌰
struct LGStruct1 {
double a; // 8 [0 7]
char b; // 1 [8]
int c; // 4 (9 10 11 [12 13 14 15]
short d; // 2 [16 17] 24
}struct1;
struct LGStruct2 {
double a; // 8 [0 7]
int b; // 4 [8 9 10 11]
char c; // 1 [12]
short d; // 2 (13 [14 15] 16
}struct2;
struct LGStruct3 {
double a; // 8 [0 7]
int b; // 4 [8 11]
char c; // 1 [12]
short d; // 2 [14 15]
int e; // 4 [16 19]
struct LGStruct1 str; // 24 [24 47] 48
} struct3;
我们先来根据对齐原则计算struct1的内存大小
- 变量
a:offset从0开始,存放位置为[0-7] - 变量
b:offset从8开始(8是数据大小1的倍数),存放位置为[8] - 变量
c:offset从9开始(9不是数据大小4的倍数,补齐到12开始),存放位置为[12-15] - 变量
d:offset从16开始(16是数据大小2的倍数),存放位置为[16-17]
我们计算出来结构体大小应该是18,遵循内存对齐原则3,18不是最大数据大小8的倍数,补齐为24,从而得到结构体struct1内存分配大小为24
struct2内存大小的计算如下:
- 变量
a:offset从0开始,存放位置为[0-7] - 变量
b:offset从8开始(8是数据大小1的倍数),存放位置为[8-11] - 变量
c:offset从12开始(11是数据大小1的倍数),存放位置为[12] - 变量
d:offset从13开始(13不是数据大小2的倍数,从14开始),存放位置为[14-15]
我们计算出来结构体大小应该是16,遵循内存对齐原则3,16是最大数据大小8的倍数,从而得到结构体struct2内存分配大小为16.
而struct3内存大小的计算如下:
- 变量
a:offset从0开始,存放位置为[0-7] - 变量
b:offset从8开始(8是数据大小1的倍数),存放位置为[8-11] - 变量
c:offset从12开始(12是数据大小1的倍数),存放位置为[12] - 变量
d:offset从13开始(13不是数据大小2的倍数,从14开始),存放位置为[14-15] - 变量
e:offset从16开始(16是数据大小4的倍数),存放位置为[16-19] - 变量
str:因为是结构体变量,遵循原则2结构体作为成员时,则结构体成员要从其内部最大元素大小的整数倍开始存储。LGStruct1中最大变量是double,8字节,20不是8的倍数,补位从24开始,存放位置为[24-42]
我们计算出来结构体实际大小应该是43,根据原则3-结构体的总大小(sizeof输出结果),必须是内部最大成员的整数倍,是最大数据大小str(8)的倍数,从而得到结构体struct3内存分配大小为48.