您的位置:首页 > 其它

内存对齐机制

2015-09-06 21:52 190 查看
我相信在网上已经有很多关于内存对齐机制的文章了,在这里,我只想通过一个小例子来阐明内存分配的现象

有这样的一段代码:

//: 内存对齐_2

#include <cstdio>

struct A {

char m1; // 1

double m2; // 8

int m3; // 4

};

int main() {

A a = {'A', 0.2, 4};

printf("sizeof(A) = %d\n", sizeof(A));

printf("A.m1 = %ld\n", long(&a.m1));

printf("A.m2 = %ld\n", long(&a.m2));

printf("A.m3 = %ld\n", long(&a.m3));

printf("-----------------\n\n");

return 0;

} ///:~



至于地址为什么是递增的就不多做解释了(编译器压入栈的顺序有关),在 VC 6.0 下进行调试,为了了解 a.m1、a.m2、a.m3 在内存中的对齐情况,先找出 a.m1 的内存地址:



这里的 0x0012ff30 就是 a.m1 的内存地址了,再来看 a.m1、a.m2、a.m3 的内存对齐情况:



图中正是 0x0012ff30 内存布局情况,其中红色框子分别表示 a.m1、a.m2、a.m3(在 32 位机上面,char 占 1 个字节,int 占 4 个字节,double 占 8 个字节,1 字节 = 8 位,每 4 位以 16 进制形式表示),浅蓝色框子表示填充部分(padding):

在 0x0012ff30 地址先存放了 char 类型的 m1,占 1 个字节(2 位),接着就要存放 double 类型的 m2,因为 m2 需要占 8 个字节(在内存对齐机制中,为了减少处理器对内存的访问次数,通常编译器都会在编译阶段对齐字节,规则是变量的内存地址必须是该变量字节数的整数倍),因此,存放完 m1 以后还要填充 7 个字节长度的内存,这样 m1 总的大小就占了 8 个字节长度;存放完 m2 以后,m3 占 4 个字节,前两者共占了
16 个字节,m3 的内存地址满足其字节倍,是不是就不需要填充呢?

如图示,答案就在图上,不是的,考虑定义结构体数组 A a[] = {0}; 编译器为了确保处理器总是一次就可以访问完一个变量,在分配内存的时候以结构体中“字节数最大的”变量进行分配,也就是满足 address + 8n;

尽管看来编译器花费了更多的内存去完成这件工作,但是对于整体的效率来说,却是获益了不少

不错的参考资料:

1. 《深入理解计算机系统》 Chapter 3 程序的机器级表示 3.9.3

2. 百度百科 http://baike.baidu.cn/view/4786260.htm

3. 内存对齐的原理,作用…… /article/3953300.html

4. C/C++内存分配与内存对齐全面探讨(比较详细,没看完) /article/1565838.html

5. 一篇讲对齐比较好的文章 http://old.uplook.cn/blog/10/109320/

6. C++内存对齐详细使用指南(不建议一开始看) http://developer.51cto.com/art/201002/183652.htm
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: