user-0 提问: 为什么要内存对齐？

回复:
user: user-1
content: 效率只是一个方面，有些甚至影响正确性。  在某些处理器上，只能采用自然对齐的访问，否则产生硬件异常，如原来Nokia的一些芯片。

user: user-2
content: 引用 10 楼 wangdahu888 的回复:无量天尊,看在你一片求知若渴之心,贫道就把这篇珍藏多年的文章送与你,细读之,必大悟!!! http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html 这篇文章很好，学了很多东西

user: user-3
content: 受益了

user: user-4
content: 内存对齐关系到结构体孔洞、追加等无效数据，还涉及到总线利用率和指令执行速度。

user: user-5
content: 因为数据传输总线是32位4个字节的。。。。这样可以保证数据传输速度。跨边界的数据会增加cpu分析数据的时间。。。

user: user-6
content: 目前新的更X的CPU对这个有什么别的用处不是很清楚，但早期的CPU之所以要求（或prefer)内存对齐是因为地址总线的条数之类的问题吧。 比如16位地址总线只能访问65536个字节的内存，但如果地址单位是4字节的话，就可以访问4位的内存大小。  拿x86来说， x86是32位寄存器，所以一次一般读取4个字节，并且读取只能从4字节边界开始。如果你访问单个字节内存，CPU会把其它3个字节扔掉。 如果你要读取两个字节，但位于4字节边界两侧，CPU需要先读前边4字节，然后扔掉三个字节，再读取后边4字节，然后再扔掉其中的三个字节，然后把两次读取的结果拼成一个双字节。 所以双字节最好对齐到双字节边界，以保证CPU一次就可以读取。 而4字节值对齐到4字节边界也是一个道理。  这也是x86牛X，直接支持非对齐读取（虽然慢点），有些CPU是不支持这种跨边界读取的，所以C语言编译器有时要生成额外代码以处理跨界读取，其效率更慢。

user: user-7
content: 一句话，提高内存地址的访问效率！

user: user-0
content: 引用 10 楼 wangdahu888 的回复:无量天尊,看在你一片求知若渴之心,贫道就把这篇珍藏多年的文章送与你,细读之,必大悟!!! http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html 图解最好了，谢啦！看到了想看到的东西！

user: user-8
content: 无量天尊,看在你一片求知若渴之心,贫道就把这篇珍藏多年的文章送与你,细读之,必大悟!!! http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html

user: user-9
content: 引用 7 楼 u011416173 的回复:[quote=引用 6 楼 caozhy 的回复:] 道理很简单，现代的处理器是超标量乱序执行的。 如果操作的数据没有对齐，那么就不能并行地写，即使它们没有相互依赖关系，但是他们位于同一个块上。你的意思是cpu只能对不同的块进行并行读写是吧。可是内存对齐有统一的标准么？偏移量不是要根据数据的类型么？那这样的块大小是固定的么？ 谢了！[/quote] 应该说，只有没有关联的块并行读写才不会出现同步问题。这个道理很简单。 假设2个步骤，步骤2依赖步骤1的结果，那么必须等步骤1执行完了才能执行步骤2。

user: user-0
content: 引用 6 楼 caozhy 的回复:道理很简单，现代的处理器是超标量乱序执行的。 如果操作的数据没有对齐，那么就不能并行地写，即使它们没有相互依赖关系，但是他们位于同一个块上。你们都很厉害，愿意抽空回答菜鸟。真心很感激。

user: user-0
content: 引用 6 楼 caozhy 的回复:道理很简单，现代的处理器是超标量乱序执行的。 如果操作的数据没有对齐，那么就不能并行地写，即使它们没有相互依赖关系，但是他们位于同一个块上。你的意思是cpu只能对不同的块进行并行读写是吧。可是内存对齐有统一的标准么？偏移量不是要根据数据的类型么？那这样的块大小是固定的么？ 谢了！

user: user-9
content: 道理很简单，现代的处理器是超标量乱序执行的。 如果操作的数据没有对齐，那么就不能并行地写，即使它们没有相互依赖关系，但是他们位于同一个块上。

user: user-0
content: 引用 2 楼 user-10 的回复:处事之道在于平衡，效率和空间不可兼得就是想了解下为什么这样会获得更高的访问效率。谢了。

user: user-0
content: 引用 1 楼 wangdahu888 的回复:普通程序员心目中的内存印象，由一个个的字节组成，而CPU并不是这么看待的。CPU把内存当成是一块一块的，块的大小可以是2，4，8，16字节大小，因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity（粒度） 本人把它翻译为“内存读取粒度” 。默认的读取粒度是4字节大小。 这个粒度可以通过#pragma pack()来调整 那么编译器是按照什么样的原则进行对齐的? １:数据成员对齐规则：结构(struct)(或联合(union))的数据成员，第一个数据成员放在offset为0的地方，以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小（只要该成员有子成员，比如说是数组，结构体等）的整数倍开始(比如int在３２位机为４字节,则要从４的整数倍地址开始存储。  ２:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)  ３:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.麻烦您了。

user: user-0
content: 引用 楼主 u011416173 的回复:能具体点说么。可以用11**1111这样的形式图解。*代表空出来的内存。这个机制我了解，但是不太清楚具体的原因。您能解释下这样访问内存效率为什么会更高么？

user: user-10
content: 处事之道在于平衡，效率和空间不可兼得

user: user-8
content: 普通程序员心目中的内存印象，由一个个的字节组成，而CPU并不是这么看待的。CPU把内存当成是一块一块的，块的大小可以是2，4，8，16字节大小，因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity（粒度） 本人把它翻译为“内存读取粒度” 。默认的读取粒度是4字节大小。 这个粒度可以通过#pragma pack()来调整 那么编译器是按照什么样的原则进行对齐的? １:数据成员对齐规则：结构(struct)(或联合(union))的数据成员，第一个数据成员放在offset为0的地方，以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小（只要该成员有子成员，比如说是数组，结构体等）的整数倍开始(比如int在３２位机为４字节,则要从４的整数倍地址开始存储。  ２:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)  ３:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.