内存对齐机制

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

有这样的一段代码:

[cpp]  view plain copy
  1. //: 内存对齐_2  
  2. #include <cstdio>  
  3.   
  4. struct A {  
  5.   char   m1;  // 1  
  6.   double m2;  // 8  
  7.   int    m3;  // 4  
  8. };  
  9.   
  10. int main() {  
  11.   A a = {'A', 0.2, 4};  
  12.   
  13.   printf("sizeof(A) = %d\n"sizeof(A));  
  14.   printf("A.m1      = %ld\n"long(&a.m1));  
  15.   printf("A.m2      = %ld\n"long(&a.m2));  
  16.   printf("A.m3      = %ld\n"long(&a.m3));  
  17.   printf("-----------------\n\n");  
  18.   
  19.   return 0;  
  20. ///:~   


至于地址为什么是递增的就不多做解释了(编译器压入栈的顺序有关),在 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. 内存对齐的原理,作用……  http://lc7cl.iteye.com/blog/1250481

4. C/C++内存分配与内存对齐全面探讨(比较详细,没看完)  http://blog.csdn.net/cuibo1123/article/details/2547442

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

6. C++内存对齐详细使用指南(不建议一开始看) http://developer.51cto.com/art/201002/183652.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在实现原子操作时,需要考虑内存对齐和缓存一致性等问题,主要可以通过以下方法进行处理: 1. 内存对齐 为了确保原子操作的正确性和效率,需要对内存进行对齐。在 C 语言中,可以使用 `__attribute__((aligned(n)))` 来指定变量的对齐方式,其中 `n` 表示对齐的字节数。例如: ```c int __attribute__((aligned(8))) a; // 以 8 字节对齐 ``` 2. 缓存一致性 为了确保原子操作的正确性,需要使用一些特殊的指令或者技术来确保数据在不同缓存之间的一致性。常见的方法包括: - 使用 CPU 提供的原子操作指令,例如 x86 平台的 `lock` 前缀指令。 - 使用一些特殊的内存屏障指令,例如 x86 平台的 `mfence` 指令和 `clflush` 指令。 - 使用锁机制,例如互斥锁和读写锁等。 下面是一个使用 GCC 内置函数 `__sync_fetch_and_add()` 实现原子操作的例子,其中使用了内存对齐和缓存一致性技术: ```c #include <stdio.h> #include <stdint.h> int main() { int32_t __attribute__((aligned(64))) value = 0; // 以 64 字节对齐 __sync_fetch_and_add(&value, 1); // 原子地对 value 加 1 printf("value = %d\n", value); return 0; } ``` 在上面的例子中,使用了 GCC 内置函数 `__sync_fetch_and_add()` 来实现原子操作,同时使用了 `aligned` 属性来指定变量的对齐方式。此外,在进行原子操作时, GCC 会自动插入一些内存屏障指令来保证缓存一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值