5

我对内存对齐的概念有点困惑。所以这是我的疑问:文本所说的是,如果你想读取 4 个字节的数据,从一个不能被 4 整除的地址开始,你就会遇到内存访问未对齐的情况。例如,如果我想从地址 05 开始读取 10 个字节,这将被称为未对齐访问 (http://www.mjmwired.net/kernel/Documentation/unaligned-memory-access.txt)。

这种情况是否特定于 4 字节字可寻址架构,或者这是否也适用于字节可寻址架构?如果上述情况对于字节可寻址架构是不对齐的,为什么会这样?

谢谢!

4

2 回答 2

4

作为一般规则,内存中的第 0 位被选通到总线上,并且该总线的第 0 位连接到每个寄存器的第 0 位。这样一直持续到第 31 位。可能有特殊的硬件将每个字节(第 15:8、23:16 和 31:24 位)引导到低位字节,即第 7:0 位。(当您到达位“32”时,它实际上是地址 4 处 4 字节字的位 0。)

但是,在标称情况下,没有任何特殊硬件可以将字节移动到除了以自然顺序标称连接到的位置之外的任何位置,也可能是字节通道 0。

想象一个具有 32 个数据引脚的简单内存芯片和一个具有 32 个数据引脚的简单 CPU。每个芯片上的给定数据引脚连接到另一个芯片上的相应数据引脚,并且仅连接到那个数据引脚。简单的 CPU根本无法进行未对齐的读取

因此,考虑从 0 读取。接下来的 4 个字节全部落入已连接的寄存器中,从地址 4 读取也会发生这种情况。但是如果从地址 1 读取(32 位)怎么办?还是2?还是3?虽然读取不能直接在硬件中完成,但一个花哨的控制器可以导致很多事情发生:

  • CPU 可以进行两次读取以获取所有位。它不能同时做,它只有 32 个引脚。一次读取来自地址 0,一次读取来自地址 4
  • 然后,CPU 必须执行各种移位、屏蔽和异或运算,以便从这两个组件中构造一个单词。

所有这些事情都需要额外的时间。


笔记。实际上,数据总线通常是 32 位的倍数,存储器也是如此。可能存在用于重新对齐对象的特殊硬件。但即便如此,因为这是一种异常情况,它可能无法获得正确对齐读取所获得的管道优化,即使使用特殊硬件,通过它运行操作数也可能会花费时间。

于 2012-04-05T01:31:39.770 回答
2

对齐与数据大小和寻址有关。大多数指令集/软件的寻址以字节为单位。0,1,2,3 都是有效的字节地址。假设您正在访问的内存系统或外围设备是“字节可寻址”的,基本上您可以向其写入单个字节,您通常有允许您使用任何地址值的指令。当你有超过一个字节时开始对齐,两个字节,如果对齐意味着地址的lsbit为零,未对齐意味着它是一。四个字节,32 位数量,低两位为零,对齐,一个或两个不为零,不对齐,依此类推。可以将其视为模数,您想要一个模数 4 = 0 在 4 字节边界上对齐的地址。

现在通常作为一名软件工程师,您不会故意让自己处于需要在地址 5 处获取 10 个字节的情况下,您可能会在 0x4 处执行 12 个字节或在 0x0 处执行 16 个字节或类似的事情,即使您只使用 10其中你会更合乎逻辑地对齐它们。外部影响、网络数据包、文件系统、共享内存、硬件等,任何时候你跨越一个编译域,你都可能不得不处理这个问题并采取相应的行动。10 个字节是半有趣的,这取决于您是尝试将这些字节复制到另一个同样糟糕的地址,还是只是读取它们或写入它们。如果阅读,您可能只想在地址 0x4 处读取 12 个字节并完成它。如果写得好,您可以在一个漂亮的循环中完成所有 10 个操作,或者一次展开一个字节,您可以在 0x5 写入一个,在 0x6 写入两个,在 0x8 写入四个,在 0xC 写入两个,在 0xE 写入一个,或一个在 0x5,一个循环或展开的 4 个 16 位值,从 0x6 开始,然后在 0xE 一个字节。等等。

既然您说阅读,您可以在 0x4 处读取 3 个 32 位数量或从 0x0 开始读取两个 64 位数量。这在很大程度上取决于您打算如何处理数据以及您使用的指令集等。10 字节读取的循环可能是最干净/最简单的读取、维护等。

如果您想知道对齐与未对齐,那么就像我上面提到的那样,您可以做一个

8 bit access at 0x5
16 bit access at 0x6
32 bit access at 0x8
16 bit access at 0xC
8 bit access at 0xE

正如我一直说的那样,对于可能不是最有效的读取。对于写入,您可以读取修改写入 32 或 64 位数量或我上面提到的组合。

于 2012-04-05T01:17:23.967 回答