对内存对齐模式的理解
在学习结构体的时候,我们在定义一个结构体,例如,
typedef struct STI {
char id[9];
char name[15];
int age;
char sex;
int score;
}STI;
STI stu = {“123456”, “zhangke”, 18, 0, 90};
经过上机验证会发现,sizeof(STI)的结果是36,而并不是33.而之所以会多出3个字节的原因就在于,内存对齐模式!
其实,内存对齐模式就是说,在内存中的所有变量的字节分配是按照1B,2B,4B或8B的倍数来分配存储空间的,而内存对齐的需要是基于“内存的页式管理”。内存的页式管理就是以页面的方式实现对内存的分配与回收,理解页式管理模式之前,需要了解“连续存储空间分配管理”模式。
“连续存储空间分配管理模式”,简单的说就是,操作系统基于“已分配空间表”和“未分配空间表”对内存空间的分配管理。我们可以通过C语言中的malloc函数和free函数来理解,malloc函数申请空间,需要提供申请的空间的大小,函数返回值是一个地址值,也就是说,我们不需要关心申请的空间的具体位置,只要提供大小即可,由操作系统为我们分配(空间足够就分配),而free函数需要我们提供首地址,不需要提供大小,因为操作系统会根据首地址在“已分配空间表”中就可以找到其对应的位置以及所占空间大小,并将其回收。
但,连续存储空间分配管理很容易造成一个问题,那就是“产生内部碎片”,会出现“假内存不足”!而对于假内存不足,可以通过“紧缩”(相当于磁盘的碎片整理),将所有碎片移动到一段并合并。但是,这个紧缩过程代价非常大。为此,就有了“页式管理”的内存分配方案。
将物理内存按照大小分割成“物理页面”,对于软件按照相同大小分割成“逻辑页面”,假设右图的灰色页面是已分配页面,则可以将软件的5个逻辑页面分配到剩余的物理页面中,并且顺序是随机的。假设按照右图给软件分配空间,可以得到一张非常关键的表:页表(按逻辑页号排列的,所申请的物理页号表),假设物理页面大小为1000字节。
现在,存在一个寻址需求,寻址3627,
定位过程可分为:
1.3627 / 1000 = 3
即3627这个地址在3逻辑页面;
2.根据页表的第四项(下标为3),其所在物理页号为6
3.3627 % 1000 = 627
在6号物理页面进行627字节的偏移即可;
事实上,物理页面大小总是2的整数次方大小,这样是为了加速计算过程。
上述的页式管理的确避免了连续存储分配产生的内存碎片,尽可能的利用内存空间,但是也存在以下问题:
1.会产生内部碎片;
2.如果数据在页面中存储,需要跨越两个逻辑页面,那就会降低寻址速度;
比如一个int类型的变量,前3个字节在2号逻辑页面,最后1个字节在3号逻辑页面,那么就得进行两次寻址。其实避免这个问题也很简单,只要int 类型的数值在内存中申请空间的首地址是4的倍数就不会跨越两个页面了。
回到我们一开始说的结构体,多出来的3个字节就在char sex这个成员这里多出来了,原因就是首地址以4的倍数,如果用UE编辑器就可以看的很清楚。
来源:CSDN
作者:Ailsa Zhang
链接:https://blog.csdn.net/Ailsazxk/article/details/103456006