Memory 32位英特尔处理器上的内存对齐

Memory 32位英特尔处理器上的内存对齐,memory,x86,alignment,32-bit,intel,Memory,X86,Alignment,32 Bit,Intel,英特尔的32位处理器(如奔腾)具有64位宽的数据总线,因此每次访问可获取8个字节。基于此,我假设这些处理器在地址总线上发出的物理地址总是8的倍数 首先,这个结论正确吗 其次,如果它是正确的,那么应该在8字节边界上对齐数据结构成员。但我见过有人在这些处理器上使用4字节对齐 这样做的理由是什么?物理总线是64位宽…8的倍数-->是 然而,还有两个因素需要考虑: 某些x86指令集是字节寻址的。有些是32位对齐的(这就是为什么有4字节的东西)。但没有(核心)指令是64位对齐的。CPU可以处理未对齐的数据

英特尔的32位处理器(如奔腾)具有64位宽的数据总线,因此每次访问可获取8个字节。基于此,我假设这些处理器在地址总线上发出的物理地址总是8的倍数

首先,这个结论正确吗

其次,如果它是正确的,那么应该在8字节边界上对齐数据结构成员。但我见过有人在这些处理器上使用4字节对齐


这样做的理由是什么?

物理总线是64位宽…8的倍数-->是

然而,还有两个因素需要考虑:

  • 某些x86指令集是字节寻址的。有些是32位对齐的(这就是为什么有4字节的东西)。但没有(核心)指令是64位对齐的。CPU可以处理未对齐的数据访问
  • 如果您关心性能,那么应该考虑缓存线,而不是主内存。缓存线要宽得多

  • 对于随机访问,只要数据没有错位(例如跨越边界),我认为这并不重要;数据中正确的地址和偏移量可以通过简单的硬件结构找到。当一次读取访问不足以获取一个值时,它会变慢。这也是编译器通常将小值(字节等)放在一起的原因,因为它们不必位于特定的偏移量;短路应为偶数地址、32位4字节地址和64位8字节地址

    请注意,如果使用缓存和线性数据访问,情况将有所不同。

    通常的经验法则(直接来自Intels和AMD的优化手册)是,每种数据类型都应根据其自身大小进行调整。
    int32
    应在32位边界上对齐,
    int64
    应在64位边界上对齐,依此类推。一个字符在任何地方都合适

    当然,另一条经验法则是“编译器已经被告知对齐要求”。您不必担心它,因为编译器知道添加正确的填充和偏移量以允许有效访问数据

    唯一的例外是在使用SIMD指令时,您必须手动确保大多数编译器上的对齐

    第二,如果它是正确的,那么 应在上对齐数据结构成员 8字节的边界。但我看到了 使用4字节对齐的用户 而是在这些处理器上


    我看不出这有什么区别。CPU只需对包含这4个字节的64位块进行读取即可。这意味着它在请求的数据之前或之后获得4个额外字节。但在这两种情况下,它只需要一次读取。32位宽数据的32位对齐确保它不会跨越64位边界。

    他们这样做是有道理的,因为更改为8字节对齐将构成ABI更改,而边际性能改进不值得费事


    正如其他人已经说过的,缓存线很重要。实际内存总线上的所有访问都以缓存线(x86上的64字节,IIRC)为单位。请参阅前面提到的“每个程序员需要了解的内存”文档。因此,实际内存流量是64字节对齐的。

    您所指的64位总线为缓存提供数据。作为CPU,始终读取和写入整个缓存线。缓存线的大小始终是8的倍数,其物理地址实际上是以8字节偏移量对齐的


    缓存到寄存器的传输不使用外部数据总线,因此该总线的宽度无关紧要。

    我不知道这个问题的意思,但我很好奇这与编程有什么关系,以及这可能会对我产生什么影响。我在哪里可以读到这种低级类型的基本介绍?请参阅“每个程序员都应该了解内存”:如何从“请求的读取总是8的倍数”到“您的数据应该总是从8字节边界开始”?我看不出它们之间有什么逻辑联系。只要数据不跨越8字节的边界,我们就很好,不是吗?我不明白。您同意像奔腾这样的处理器在地址总线上只放8的倍数。然后你说4字节对齐是可以的。好的,考虑地址0x090044 44。虽然它是4字节对齐的,但处理器永远不会在地址行上发出这个地址,因为它不是8的倍数。因此,在此地址提取内存将需要两次提取。那么4字节对齐是如何被证明的呢?为什么需要两次抓取呢?它只需要请求从0x00004440到0x000044447的所有数据,既然我们对0x00004444-0x000044447感兴趣,那么问题出在哪里?为什么要谈论指令对齐,这毫无意义。使用NOPs将指令填充到某个边界无法实现任何功能。x87指令可以进行64位加载/存储(包括64位整数数据的
    fild
    /
    fistp
    ),奔腾集成了这一功能。奔腾的
    也可以锁定cmpxchg8b
    ,如果它跨越缓存线边界,速度会非常慢。不过,没有指令需要32位对齐。它们只是受益于不跨越缓存线边界进行拆分。如果4个字节跨越一个64位块到下一个64位块,则不会。如果它在4个字节边界上对齐,会发生什么情况?我不敢相信我错过了这个简单的推理。当您使用4字节实现相同的性能时,为什么还要在8字节对齐中浪费4个额外字节?谢谢你,杰尔夫。你说得很有道理。@jalf我发布了一个与对齐相关的不同问题(在本例中,关于大小小于体系结构大小的单词),我不确定你回答中应用的推理是否适用于我的问题:“编译器已经被告知对齐要求”。但是编译器也被赋予了它必须遵守的语言规范,对于C语言来说,这意味着没有成员重新排序。在许多平台上,重新排列结构成员可以提高性能