【问题标题】:x86 Memory Alignment of struct vs. cache line?结构与缓存行的x86内存对齐?
【发布时间】:2021-12-02 00:44:58
【问题描述】:

最近我正在开发一个“搜索系统”,而关于内存/缓存性能的一些事情让我感到困惑。 假设我的机器信息:x86 架构(L1-3 缓存,64 字节缓存线),Linux 操作系统

CPU每次读取64个字节(缓存行),那么CPU从内存地址(到缓存)读取数据总是64倍吗?例如0x00(到0x3F),0x40(到0x7f)。如果我需要位于 0x20 的数据(int32_t),那么系统仍然需要加载 0x00--0x3F。 这个案例怎么样:
struct Obj{int64_t a[5];char b[2];}; 然后定义
int64_t c[5]; Obj obj; int64_t d;
虚拟内存(或物理内存?)会这样组织吗?

【问题讨论】:

  • 这是两个截然不同的问题。请专注于其中一个。
  • 我删除了关于 Linux 的平板分配器的完全独立的问题。如果需要,请单独询问。现有答案仅解决了我在编辑后留下的一个问题。

标签: c++ c x86 memory-alignment cpu-cache


【解决方案1】:

我认为您可能缺少的部分是编译器对各种类型的对齐要求。

整数类型通常对齐到它们自身大小的倍数(例如,64 位整数将对齐到 8 个字节);所谓的“自然对齐”。这不是 x86 的严格架构要求;未对齐的加载和存储仍然有效,但由于它们的效率较低,编译器更愿意避免它们。

聚合,如struct,根据其成员的最高对齐要求进行对齐,如果需要,将在成员之间插入填充以确保每个成员都正确对齐。填充也将添加到末尾,以便struct 的整体大小是其所需对齐的倍数。

因此,在您的示例中,struct Obj 对齐为 8,其大小将四舍五入为 48(末尾有 6 个字节的填充)。所以不需要在c[4] 之后插入 24 个字节的填充(我认为您的意思是在地址 40-63 处写入填充);你的obj 可以放在地址 40。d 然后可以放在地址 88。

请注意,这些都与缓存行大小无关。默认情况下,对象不与缓存行对齐,尽管“自然对齐”将确保没有整数加载或存储必须跨越缓存行。

【讨论】:

  • 感谢我的 Q 并非常感谢我,“我认为你的意思是在地址 40-63 处写填充”你是对的,我的错误。另外,关于加载内存到 cpu-cache 的 cpu 硬件行为是什么,起始地址总是 64 的倍数?
  • 是的,缓存行对齐到 64 字节,所以缓存行的起始地址是 64 的倍数。(否则缓存行可能会重叠,这会使事情变得非常复杂。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 2011-11-09
  • 2012-06-26
相关资源
最近更新 更多