数据成员对齐原则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员(正在放的这个变量)大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)
前提:没有pragma pack宏 控制
,自定义对齐基数:#pragma pack
一个诡异的现象
先上一个例子,大家先运行一下看看
结果(同样的成员类型,变换一下位置,整个结构体的长度竟然不一样):
内存对齐原则
- 结构体变量的
首地址
能够被其最宽基本类型成员大小
与对齐基数
中的较小者整除
- 结构体每个成员相当于
结构体首地址
的偏移量
都是该成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在成员之间加上填充字符 - 结构体的总大小为结构体
最宽基本类型成员大小
与对齐基数
中的较小者
的整数倍,如有需要编译器会在最末一个成员后加上填充字符
why use this principle?
平台原因
不是所有硬件平台都可以访问任意地址上的任意数据;某些硬件平台只能在某些地址获取某些指定类型的数据,否则抛出硬件异常。
性能原因
数据结构应该尽可能的在自然边界上对齐,为了访问未对其的内存,处理器需要做两次内存访问,而对齐的内存访问只需要一次就 ok
剖析栗子
回过头来看看最上方的栗子,按道理说 sizeof(str1) 和 sizeof(str2) 应该都一样,1(char) + 2(short) + 4(int) = 7,而实际上一个排列不一样,一个是 8 一个是 12;我们猜测就是编译经过什么操作,使得结构体的内存变大了;Yes,这个操作就是 内存对齐
。
so,我们就来剖析一下这个原因,根据之前我们总结的内存对齐的规则,每个数据成员的偏移量必须是 对齐基数
和 成员数据大小
之中的 最小值
,即 min(对齐基数, 成员数据大小)
,而 对齐基数 (一般由 #pragma pack(n) 进行设置,n表示设置为n字节对齐) VC6默认的是8字节对齐。
以 str1 为例:
- char 占1个字节,起始偏移量为 0;
- short 占2个字节,根据 min(对齐基数[8字节], 成员数据大小[short 2字节]) = 2字节 原则,这个short成员的偏移量 需要是 2 的倍数,所以编译器会在 char 后填充 一个直接的额外字节,保证后面 short 的偏移量为 2 的倍数;
- int 占 4个字节,根据 第二条同样的对齐原则,偏移量应该是 4 的倍数,刚好前面两个成员占用了 4个字节,字节从后面进行偏移添加
|
|
而 str2 的结构按照上述方法进行分析:
|
|
另外关于数组这种比较大的栗子我们也来分析一个:
我们来分步骤分析,这次字节数比较多,就不画图了:
- bookinfo 成员,int 占 4个字节,偏移量0,满足对齐原则,二维数组;此成员占:4 3 5 = 60
- isbn 成员,char 占 1 个字节,偏移量60,满足对齐原则;但是下一个成员float占4个字节,偏移量 60 + 21 = 81,不满足 4 的倍数,所以这个成员需要补足;此成员占:1 * 21 + 3= 24
- price 成员,float 占 4个字节,偏移量 60 + 24 = 84,满足 4 的倍数;此成员占:4 = 4
- name 成员,char 占 1个字节,偏移量 60 + 24 + 4 = 88,满足对齐原则;此成员占:1 * 20 = 20
- address1 成员,float 占 4个字节,偏移量 60 + 24 + 4 + 20 = 108,满足 4 的倍数;此成员占:4 = 4
- address2、address3 同样道理;此二个成员占:4 + 4 = 8
- 结构体里成员占用空间为 60 + 24 + 4 + 20 + 4 + 4 + 4 = 120,而结构体为数组,120 * 3 = 360
神器:valgrind
系统编程中一个重要的方面就是有效地处理与内存相关的问题。我们的工作越接近系统,就需要面对越多的内存问题。有时这些问题非常琐碎,而更多时候它会演变成一个调试内存问题的恶梦。所以,在实践中会用到很多工具来调试内存问题。所以就有了:最流行的开源内存管理框架 VALGRIND
摘自 Valgrind.org:
Valgrind是用于构建动态分析工具的探测框架。它包括一个工具集,每个工具执行某种类型的调试、分析或类似的任务,以帮助完善你的程序。Valgrind的架构是模块化的,所以可以容易地创建新的工具而又不会扰乱现有的结构。
常用 Valgrind Memcheck 进行内存分析:
这里就不对这个工具介绍太多,后续 wettper 会专门针对这个工具进行详细说明讲解...
本文作者: wettper
本文链接: http://www.web-lovers.com/c-memory-alignment.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!