内存对齐详解

来源:互联网 发布:杭州网络推广排名 编辑:程序博客网 时间:2024/06/09 23:59

首先定义两个结构体如下,我们看一下两个结构体大小:

#include <iostream>using namespace std;struct A{    int a;    char b;    short c;};struct B{    char b;    int a;    short c;};int main(){    cout <<"sizeof(struct A): "<< sizeof(struct A) << endl;    cout << "sizeof(struct B): " << sizeof(struct B) << endl;    return 0;}

这里写图片描述
从上面结果可以看出,两个完全相同的结构体,只是因为成员变量声明顺序不同,导致结构体所占内存的大小就不同,为什么呢?这就是因为内存对齐的原因。
什么是内存对齐?为什么需要内存对齐?对齐有什么好处?
是我们程序员来手动做内存对齐呢?还是编译器在进行自动优化的时候完成这项工作?

首先,我们需要知道内存对齐不是程序员动手做的,而是编译器自动优化完成的。那么按照正常情况,上述的结构体大小应该为4(int)+1(char)+2(short)等于7,
为什么A和B都不是7而且还不相同呢?这就是编译器优化所做的处理。数据在内存中存储是会按照一种数据对齐的规则进行存储。
内存对齐规则:
(1)结构体中的第一个变量位于内存中偏移量为0的位置,接着以后的每个变量所对应的偏移量都必须是该变量本身所占用字节数的整数倍。
(2)该结构体整体占用内存大小必须是结构体中占用最大内存变量的字节数的整数倍。
我们从A和B内存结构图再深入理解一下内存原则
这里写图片描述
内存对齐的作用:
(1)不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
(2)经过内存对齐之后,CPU的内存访问速度大大提升。具体原因如下:
CPU在读取内存数据时是按块读取的,一般快的大小可以是2、4、8、16个字节。这里我们假设CPU是按4个字节块读取的,还是以上面的struct B为例如果没有内存对齐,要读取变量a的值,先要从前四个字节读取,然后再读取第二个块,这个时候a的存储分别在这个两块内存中,CPU需要做处理将这两块拿出来拼接在一起读取变量a的值,想一下这样会很麻烦,大大降低了CPU的效率。更糟糕的是有些部分CPU遇到内存未对齐的情况可能会停止工作。
这种内存对齐的方法表面上看占用了更多的内存,但是大大提高了CPU的工作效率,这是一种牺牲空间换取时间的思想。

下面有每种数据在不同系统下所占用的内存大小,以及字节对齐大小。
在X86,32位系统下基于Microsoft、Borland和GNU的编译器,有如下数据对齐规则:
a、一个char(占用1-byte)变量以1-byte对齐。
b、一个short(占用2-byte)变量以2-byte对齐。
c、一个int(占用4-byte)变量以4-byte对齐。
d、一个long(占用4-byte)变量以4-byte对齐。
e、一个float(占用4-byte)变量以4-byte对齐。
f、一个double(占用8-byte)变量以8-byte对齐。
g、一个long double(占用12-byte)变量以4-byte对齐。
h、任何pointer(占用4-byte)变量以4-byte对齐。

而在64位系统下,与上面规则对比有如下不同:
a、一个long(占用8-byte)变量以8-byte对齐。
b、一个double(占用8-byte)变量以8-byte对齐。
c、一个long double(占用16-byte)变量以16-byte对齐。
d、任何pointer(占用8-byte)变量以8-byte对齐。

原创粉丝点击