原文: http://blog.csdn.net/liupeng900605/article/details/7530010

首先由一个程序引入话题:

 1 //环境:vc6 + windows sp2
 2 //程序1
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 struct st1 
 8 {
 9     char a ;
10     int  b ;
11     short c ;
12 };
13 
14 struct st2
15 {
16     short c ;
17     char  a ;
18     int   b ;
19 };
20 
21 int main()
22 {
23     cout<<"sizeof(st1) is "<<sizeof(st1)<<endl;
24     cout<<"sizeof(st2) is "<<sizeof(st2)<<endl;
25     return 0 ;
26 }
27 

程序的输出结果为:

sizeof(st1) is 12

sizeof(st2) is 8

问题出来了,这两个一样的结构体,为什么sizeof的时候大小不一样呢?

本文的主要目的就是解释明白这一问题。

内存对齐,正是因为内存对齐的影响,导致结果不同。

对于大多数的程序员来说,内存对齐基本上是透明的,这是编译器该干的活,编译器为程序中的每个数据单元安排在合适的位置上,从而导致了相同的变量,不同声明顺序的结构体大小的不同。

那么编译器为什么要进行内存对齐呢?程序1中结构体按常理来理解sizeof(st1)和sizeof(st2)结果都应该是7,4(int) + 2(short) + 1(char) = 7 。经过内存对齐后,结构体的空间反而增大了。

在解释内存对齐的作用前,先来看下内存对齐的规则:

<!--[if !supportLists]-->1、  <!--[endif]-->数据成员各自对齐:对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。

<!--[if !supportLists]-->2、  <!--[endif]-->结构(或联合)本身也要进行对齐:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

#pragma pack(n) 表示设置为n字节对齐。 VC6默认8字节对齐

以程序1为例解释对齐的规则 :

St1 :char占一个字节,起始偏移为0 ,int 占4个字节,min(#pragma pack()指定的数,这个数据成员的自身长度) = 4(VC6默认8字节对齐),所以int按4字节对齐,起始偏移必须为4的倍数,所以起始偏移为4,在char后编译器会添加3个字节的额外字节,不存放任意数据。short占2个字节,按2字节对齐,起始偏移为8,正好是2的倍数,无须添加额外字节。到此规则1的数据成员对齐结束,此时的内存状态为:

oxxx|oooo|oo

0123 4567 89 (地址)

(x表示额外添加的字节)

共占10个字节。还要继续进行结构本身的对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行,st1结构中最大数据成员长度为int,占4字节,而默认的#pragma pack 指定的值为8,所以结果本身按照4字节对齐,结构总大小必须为4的倍数,需添加2个额外字节使结构的总大小为12 。此时的内存状态为:

oxxx|oooo|ooxx

0123 4567 89ab  (地址)

到此内存对齐结束。St1占用了12个字节而非7个字节。

St2 的对齐方法和st1相同,读者可自己完成。

内存对齐的主要作用是:

<!--[if !supportLists]-->1、  <!--[endif]-->平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

<!--[if !supportLists]-->2、  <!--[endif]-->性能原因:经过内存对齐后,CPU的内存访问速度大大提升。具体原因稍后解释。

图一:

这是普通程序员心目中的内存印象,由一个个的字节组成,而CPU并不是这么看待的。

图二:

CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度)本人把它翻译为“内存读取粒度” 。【原文::memory access granularity,computer's processor  accesses memory in two-, four-, eight- 16- or even 32-byte chunks,不同CPU 粒度可能不一样

假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论:

<!--[if !supportLists]-->1、<!--[endif]-->数据从0字节开始

<!--[if !supportLists]-->2、<!--[endif]-->数据从1字节开始

再次假设内存读取粒度为4。

图三:

当该数据是从0字节开始时,很CPU只需读取内存一次即可把这4字节的数据完全读取到寄存器中。

当该数据是从1字节开始时,问题变的有些复杂,此时该int型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。

图四:

此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。

这还属于乐观情况了,上文提到内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分CPU肯干,其他一部分CPU遇到未对齐边界就直接罢工了。

原文地址:http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html

补充:

什么是对齐,以及为什么要对齐:

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。 对齐的实现 通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择时候目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。 但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。

  作用:指定结构体、联合以及类成员的packing alignment;   语法:#pragma pack( [show] | [push | pop] [, identifier], n )   说明:1,pack提供数据声明级别的控制,对定义不起作用;2,调用pack时不指定参数,n将被设成默认值;3,一旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降;   语法具体分析:1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16

内存对齐是什么?为什么要内存对齐?相关推荐

  1. 语言结构体在内存的分布_结构体内存对齐,这篇文章给你彻底搞会!(干货收藏)...

    脚本之家 你与百万开发者在一起 公众号:C语言编程 作者:薛定谔的coding猫 一.内存对齐的原因  1.平台原因(移植原因):一些资料上是这样说的,"不是所有的硬件平台都能访问任意地址上 ...

  2. C字节对齐与C++类对象内存布局

    一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...

  3. C语言 | 内存对齐02 - 为什么会有内存对齐?它解决了什么问题

    文章目录 一.前言 二.内存对齐为4个字节的好处 三.内存对齐的目的是以空间换取速度 3.1.内存对齐为4的例子 3.2.内存没有使用内存对齐的例子 四.掌握内存对齐的必要性 一.前言 内存对齐的目的 ...

  4. 【高性能计算】为什么内存需要8字节或16字节对齐

    "8字节对齐"的对象存储在以8为倍数的内存地址中. 许多CPU只会从对齐的位置加载一些数据类型:在诸多CPU上,这样的访问速度更快.使用内存对齐还有其他几个可能的原因--如果没有看 ...

  5. android内存池,两种常见的内存管理方法:堆和内存池

    描述 本文导读 在程序运行过程中,可能产生一些数据,例如,串口接收的数据,ADC采集的数据.若需将数据存储在内存中,以便进一步运算.处理,则应为其分配合适的内存空间,数据处理完毕后,再释放相应的内存空 ...

  6. 整数边界对齐方式_嵌入式基础——字节对齐

    字节对齐 一.内存访问对齐规则 从高级语言的视角看,内存访问是是字节为单位的. 但是从CPU角度看,内存访问粒度与指令有关,比如1字节访问,2字节访问,4字节访问,8字节访问等. 如果在编程过程中不注 ...

  7. 对齐方式有那些_字节对齐不慎引发的挂死问题

    前言 之前程序是32位的,切到64位之后,一些隐藏的问题就暴露了.这不,一个由字节对齐导致的挂死问题就出来了. 字节对齐和64位 关于字节对齐,可参考<理一理字节对齐的那些事>,而之前也分 ...

  8. java内存区域_JVM学习之—Java内存区域

    为了加深对Java语言的理解,加深对Java虚拟机工作机制.底层特性的了解和掌握,准备在闲暇时间,抽空对<深入理解Java虚拟机 JVM高级特性与最佳实践>一书进行学习.本文是学习此书第2 ...

  9. 读取当前linux进程内存_(笔记)Linux上的内存分配

    作者: LemonNan 原文: https://juejin.im/post/5ee3c34a518825430c3ad31d 前言 本篇是对Linux内存分配的一个学习笔记. 程序内存结构 下面是 ...

  10. python内存模型_内存篇3:CPython的内存管理架构-L2-块

    本篇用到了C/C++的内存对齐的基础知识,我已经假定你有C/C++内存管理的相关基础. 我们在前一篇的流程图中留下了两个黑箱子,会涉及到内存模型第一层以上的其他话题,回顾下面关于第一层面向类型的内存A ...

最新文章

  1. 2.2版本发布!TensorFlow推出开发者技能证书
  2. [SOA征文]SOA如何起步?
  3. A Self-Attention Setentence Embedding 阅读笔记
  4. Oracle数据库导入导出命令imp/exp
  5. 不同的寻址方式的应用——将每行的单词都变成大写
  6. es dsl多条件组合查询(转)
  7. Awesome Tools Site
  8. mysql查看连接数命令_Mysql 查看连接数,状态
  9. javascript捕获事件event
  10. 男生看女生叫审美,女生看男生叫好色之新解
  11. mybatis源码详解
  12. ActiveMQ使用教程
  13. 36D杯CTF Re WP
  14. Rust语言——Package、Crate、Module
  15. java web 开发问题总结 1 原创-胡志广
  16. 飞思卡尔智能车 电机PID
  17. vue element ui表格下载成xlsx工作表格
  18. 名词解释---权益类资产
  19. MIT 计算机操作环境导论Missing Semester Lesson 9 安全和密码学
  20. IAP15F2K61S2单片机引脚图

热门文章

  1. 一次性奖金是否选择并入综合所得测算表
  2. 唱歌发声的基础知识与训练方法
  3. GoLand/GO项目配置与使用
  4. 搜狗云输入法、Google手机语音搜索:两款创新云产品
  5. python 实例 cadu_求CAD实例
  6. 【通俗易懂的通信】信道编码之——汉明码
  7. 自动化运维学习--python
  8. Python自动化运维
  9. 单片机:看门狗程序简介
  10. python怎么做图表好看_如何制作有趣好看的数据可视化图表?