什么是内存对齐
从一个例子开始
1 |
|
打印的结果是16,1,4,8。我们发现结构体占用内存的总量并不是其包含的所有元素占用内存的和,这是为什么呢,这就涉及到指针对齐的问题。对齐有两个原则:
1、结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。
比如上面的例子,首先系统会将字符串变量a存入第0个字节(相对地址,指结构体内存开辟的首地址);然后存放整型变量b时,会以4个字节为单位进行存储,由于第一个四字节模块已有数据(a),因此它会存入第二个四字节模块,即4~8字节;同理,存放双精度实例变量c时会以8个字节为单位存储,也就是会找到第一个空的且是8的整数倍的位置开始存储,这个例子中由于第一个8字节模块已被占用,所以将c存入第二个8字节模块。
再看下面这个例子
1 | struct A{ |
这个例子只是互换了b和c的类型,但是结果确不同sizeof(A2)=24,按照第一个规则结果应该是20啊,这是为什么呢,下面就看第二个规则
2、在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。
第二个例子根据第一条规则计算的结果是20但是不是double类型宽度(8)的整数倍,所以补齐到24。
内存对齐的作用
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
这点应该很容易理解,不做解释了。
2、 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。
CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度)。
假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论:
1、数据从0字节开始
2、数据从1字节开始
假设内存读取粒度为4。当数据从0字节开始时,CPU只需读取内存一次即可吧这4字节的数据完全读取到寄存器中。当该数据是从1字节开始时,问题变得有些复杂,此时该int型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。
此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。
这还属于乐观情况了,上文提到内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分CPU肯干,其他一部分CPU遇到未对齐边界就直接罢工了。
参考链接
http://blog.csdn.net/liukun321/article/details/6974282/
http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html