如何在 C 中获取 CPU 的内存粒度?
假设我想分配一个数组,其中所有元素都正确对齐内存。我可以将每个元素填充到一定大小 N 来实现这一点。我怎么知道N的值?
注意:我正在尝试创建一个内存池,其中每个插槽都是内存对齐的。任何建议将不胜感激。
如何在 C 中获取 CPU 的内存粒度?
假设我想分配一个数组,其中所有元素都正确对齐内存。我可以将每个元素填充到一定大小 N 来实现这一点。我怎么知道N的值?
注意:我正在尝试创建一个内存池,其中每个插槽都是内存对齐的。任何建议将不胜感激。
如何在 C 中获取 CPU 的内存粒度?
首先,您阅读指令集架构手册。它可以指定某些指令需要某些对齐,甚至某些指令中的寻址形式不能表示未对齐的地址。它可以指定有关对齐的其他属性。
其次,您阅读处理器手册。它可以指定性能特征(例如支持未对齐的加载或存储,但可能比对齐的加载或存储更慢或使用更多资源),并且可以指定指令集架构允许的各种选项。
第三,阅读操作系统文档。一些体系结构允许操作系统选择与对齐相关的功能,例如是否使未对齐的加载和存储失败或受支持,尽管性能比对齐的加载或存储慢。操作系统文档应包含此信息。
对于许多编程情况,您需要知道的不是 CPU 的“内存粒度”,而是您使用的 C 实现(或您使用的任何语言)的对齐要求。而且,在大多数情况下,您不需要直接了解对齐要求,而只需要遵循有关管理对象的语言规则——使用具有声明类型的对象,不要使用强制转换在不兼容类型之间转换指针,超出特定规则允许的范围它,使用适当对齐的内存,malloc
而不是调整你自己的字节指针,等等。遵循这些规则将为程序中的对象提供良好的对齐。
在 C 中,当您定义一个数组时,元素大小将自动成为 C 实现对其对齐所需的大小。例如,long double x[100];
可以为每个数组元素使用 16 个字节,即使硬件仅使用 10 个字节来存储long double
. 或者,对于struct foo
您定义的任何内容,编译器将根据需要在结构中自动包含填充以提供所需的对齐方式,并且任何数组struct foo x[100];
都已经包含该填充。sizeof(struct foo)
将与 相同sizeof x[0]
,因为每个结构对象都有内置的填充,即使只是针对单个结构对象,而不仅仅是针对数组中的元素。
当您确实需要知道 C 实现对类型所需的对齐方式时,您可以使用 C 的_Alignof
运算符。该表达式_Alignof(type)
提供 所需的对齐方式type
。
…正确的内存对齐。
正确对齐是度数问题:
使用 64 字节。
数据以称为高速缓存行的单元从内存中加载和存储。如果您的程序仅在缓存行中加载部分数据,则整行将被加载到 CPU 缓存中。也许更重要的是,用于在多核 CPU 中的核之间移动数据的算法在完整的高速缓存行上运行。将数据与缓存行对齐可以避免错误共享,即缓存行在内核之间反弹的情况,因为它包含由不同线程操作的数据。
过去,缓存行取决于架构,从 16 字节到 512 字节不等。但是,所有当前的处理器(Intel、AMD、ARM、MIPS)都使用 64 字节的高速缓存行。
这在很大程度上取决于您使用的 cpu 微架构。
在很多情况下,操作符的内存地址应该是操作数大小的倍数,否则执行会很慢(甚至可能抛出异常)。
但也有一些 CPU 根本不关心内存中操作数的特定对齐方式。
通常,C 编译器会为您关心这些细节。但是,您应该确保编译器采用正确的目标(微)架构,例如通过使用正确的编译器标志(-march=?
在 gcc 上)指定它。