有人能给我一个简短而合理的解释,说明为什么编译器为了对齐其成员而向数据结构添加填充?我知道这样做是为了让CPU可以更高效地访问数据,但我不明白为什么会这样。为什么数据结构对齐对于性能很重要?
如果这只与CPU有关,为什么在Linux中8个字节对齐的双4字节和Windows对齐8个字节?
有人能给我一个简短而合理的解释,说明为什么编译器为了对齐其成员而向数据结构添加填充?我知道这样做是为了让CPU可以更高效地访问数据,但我不明白为什么会这样。为什么数据结构对齐对于性能很重要?
如果这只与CPU有关,为什么在Linux中8个字节对齐的双4字节和Windows对齐8个字节?
对齐有助于CPU以有效的方式获取来自存储器的数据:以下高速缓存未命中/冲洗,更少的总线事务等
一些存储器类型(例如RDRAM,DRAM等)需要以结构化的要被访问方式(对齐“单词”和“突发事务”,即一次处理多个单词)以产生有效的结果。这是由于许多事情当中其中:
“填充”用于纠正数据结构的对齐以优化传输效率。
换句话说,访问“错位”结构会降低整体性能。一个很好的例子就是:假设一个数据结构是错误对齐的,并且要求CPU /内存控制器执行2个总线事务(而不是1个)以获取所述结构,所以性能因此较低。
CPU以4字节为单位从内存中提取数据(实际上它取决于硬件的某些类型的硬件的8或其他值,但让我们坚持4以保持它简单), 一切都很好,如果数据从一个可以被4除的地址开始,CPU进入内存地址并加载数据。
现在假设在不可分割由4说为了简单在地址1的缘故一个地址的数据开始时,CPU必须把从地址0的数据,然后应用一些算法在0地址转储字节,从而获得访问字节1处的实际数据。这需要时间并因此降低性能。所以将所有数据地址对齐更有效率。
缓存行是缓存的基本单位。通常它是16-64字节或更多。
Pentium IV:64字节; Pentium Pro/II:32字节; Pentium I:32字节; 486:16字节。
myrandomreader:
; ...
; ten instructions to generate next pseudo-random
; address in ESI from previous address
; ...
MOV EAX, DS:[ESI] ; X
LOOP myrandomreader
对于存储器读跨2个高速缓存行:
(为L1高速缓存未命中)的处理器必须等待整个高速缓存行1至从L2-> L1被读入之前,在处理器可以请求第二高速缓存行,从而导致短的执行失速
(用于L2高速缓存未命中)的处理器必须等待两个脉冲串从L3高速缓存(如果存在)或主存储器中读取来完成,而不是一个
个处理器档位
随机4字节读取跨越高速缓存行边界的时间约5%为64个字节的超高速缓存行,对于32分字节的人10%和16分字节的人20%。
对于未对齐数据的某些指令,即使它位于缓存行内,也可能存在额外的执行开销。这是在英特尔网站上讨论的一些SSE指令。
如果您自己定义结构,查看将所有< 32位数据字段一起列在struct
中以便减少填充开销或者查看打开还是关闭打包效果更好对于特定的结构。
在MIPS和许多其他平台上,您没有得到选择并且必须对齐 - 如果您不需要内核异常!
比对也不管额外特意给你,如果你是在公共汽车上做I/O或使用原子操作,如原子递增/递减或者如果你希望能够给你的代码移植到非Intel。
在只有英特尔(!)代码上,通常的做法是为网络和磁盘定义一组打包结构,并为内存中定义一组填充结构,并在这些格式之间转换数据的例程磁盘和网络格式的“endianness”)。
有两个独立但相关的问题:数据比对和数据结构的填充 – 2010-01-05 13:21:03
GCC对齐8个字节dobules以及在x86机器上,虽然,同微软的编译器。 – nos 2010-01-05 13:38:46
如果CPU以4字节块读取数据,为什么双8字节对齐?那么双倍是8或4字节对齐应该没关系,不是吗? – Mat 2010-01-05 13:51:56