为什么处理器只读取对齐的地址

问题描述 投票:0回答:2

所以我读了几篇关于内存对齐的文章(以及 StackOverflow 上的一些问题),我理解了为什么这样的结构:

struct A
{
  char c;
  int i;
}

会有填充物。 此外,很明显,如果处理器只能从对齐的偏移量中读取,则从未对齐的内存中获取数据会更慢。

但是为什么处理器只能从对齐的内存中读取?为什么它不能从随机地址读取数据?你知道,从随机存取存储器......

memory alignment processor
2个回答
0
投票

我取决于处理器。有些处理器根本不允许未对齐的访问。其他处理器可以,但速度往往较慢。

在您的示例中(如果字段被打包并且允许未对齐访问,如果处理器尝试读取 i,通常需要从内存中获取它。

某些处理器会因多次访问而检索未对齐的数据而影响性能。其他人根本不允许。


0
投票

处理器针对最常见的用例进行了优化:数据正确对齐时。这就是为什么对齐读取是首选的原因。

但这并不能回答你的问题。是什么让对齐读取更有效?

答案是,现代处理器不喜欢从内存中读取数据。他们从缓存中读取数据,速度要快几个数量级。

那些使用“缓存线”组织的缓存。典型的缓存行为 64 字节,并且始终与其大小对齐,您可以在here读取精确值。当您读取对齐值时,可以保证大小小于或等于缓存行的值将位于单个缓存行中。对于未对齐的值,可能部分值在缓存中,而其他部分只能从 RAM 访问。 更新:更详细的解释。

考虑在具有 64 字节缓存行的现代 x86_64 处理器上运行的此类代码:

movq rax, qword ptr [rdi]

它正在从指针
rdi

读取64位数字到寄存器

rax
如果 

rdi

正确对齐(意味着它可以被 8 整除),则保证它位于单个缓存行中。查看所有 8 个可能位置的可视化图表:

  CACHE LINE
+--------------------------------------------------------------------------+
|  0 <- offset       8                 16                24                |
| +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+  |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |  |
| +-+-+-+-+-+-+-+-- +-+-+-+-+-+-+-+-- +-+-+-+-+-+-+-+-- +-+-+-+-+-+-+-+--  |
|                                                                          |
|  32                36                44                52                |
| +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+  |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |  |
| +-+-+-+-+-+-+-+-- +-+-+-+-+-+-+-+-- +-+-+-+-+-+-+-+-- +-+-+-+-+-+-+-+--  |
|                                                                          |
+--------------------------------------------------------------------------+

因此,如果发生缓存未命中,它将仅限于单个缓存,因为当获取缓存时,它会立即获取我们值的整个 8 个字节。

如果值错位,我们可能会遇到这样的情况:

+--------------------+------------------+ |Cache line 1 | Cache line 2 | | +-+-+-+---+-+-+-+ | | | | | | | | | | | | | +-+-+-+---+-+-+-+ | | | | +--------------------+------------------+

如果我们的值跨越缓存行之间的边界,CPU 将需要从内存加载两倍的数据(2 个完整的缓存行)。

同样的情况也适用于页面错误,但我预计,特定读取导致 2 个 TLB 丢失的机会相当罕见。

此外,当您对未对齐的值进行内存

写入

时,情况可能会更糟,因为存在CPU缓存失效协议,并且此类写入将使两个缓存线无效。如果经常从多个线程访问这样的缓存行,情况会更糟。事实上,许多使用原子整数的高效同步机制通常将它们与 64 位对齐,以避免不必要的缓存失效。 例如,参见横梁

CachePlated

© www.soinside.com 2019 - 2024. All rights reserved.