我理解访问内存以使其对齐意味着什么,但我不明白为什么这是必要的。例如,为什么我可以从一个地址访问一个字节,0x…1
但我不能从同一个地址访问一个半字(两个字节)。
同样,我明白,如果您有一个地址A
和一个大小对象s
,则访问是对齐的 if A mod s = 0
。但我只是不明白为什么这在硬件层面很重要。
我理解访问内存以使其对齐意味着什么,但我不明白为什么这是必要的。例如,为什么我可以从一个地址访问一个字节,0x…1
但我不能从同一个地址访问一个半字(两个字节)。
同样,我明白,如果您有一个地址A
和一个大小对象s
,则访问是对齐的 if A mod s = 0
。但我只是不明白为什么这在硬件层面很重要。
硬件复杂;这是一个简化的解释。
典型的现代计算机可能具有 32 位数据总线。这意味着 CPU 需要执行的任何获取操作都将获取特定内存地址的所有 32 位。由于数据总线无法获取小于 32 位的任何内容,因此地址总线上甚至不使用最低两个地址位,因此就好像 RAM 被组织成一个 32 位字序列而不是 8 位字节.
当 CPU 读取单个字节时,总线上的读取周期将获取 32 位,然后 CPU 将丢弃其中的 24 位,将剩余的 8 位加载到任何寄存器中。如果 CPU 想要获取未在 32 位边界上对齐的 32 位值,它有几个通用选择:
我使用过的各种 CPU 都采用了所有这四种路径。通常,为了获得最大的兼容性,将所有 n 位读取对齐到 n 位边界是最安全的。但是,如果您确定您的软件将在具有已知未对齐读取行为的特定 CPU 系列上运行,您当然可以走捷径。即使可以进行非对齐读取(例如在 x86 系列 CPU 上),它们也会变慢。
计算机总是读入一些对齐的固定大小的块。
所以,如果你没有在内存中对齐你的数据,你可能不得不阅读不止一次。
例子
所以,基本上是为了加快速度。
所有对齐规则的原因是缓存线的不同宽度(指令缓存确实有 16 字节线用于 Core2 架构,数据缓存确实有 64 字节线用于 L1 和 128 字节线用于 L2)。
因此,如果要存储/加载跨越 Cahce 线边界的数据,则需要加载和存储两条缓存线,这会影响性能。因此,您只是因为性能受到影响而不要这样做,就这么简单。
尝试读取串行端口。数据为 8 位宽。优秀的硬件设计师确保它位于单词的最低有效字节上。
如果你有一个 C 结构的元素不是字对齐的(从向后兼容性或内存保护说),那么结构中任何字节的地址都不是字对齐的。