对齐对C++11中的性能真的很重要吗

Does alignment really matter for performance in C++11?

本文关键字:真的 性能 C++11 对齐      更新时间:2023-10-16

对齐对C++11中的性能真的很重要吗?

Stroustrup的书中有一条建议,要对结构中的成员进行排序从最大到最小。但我想知道是否有人已经进行了测量,以实际查看这是否有任何差异,以及在编写代码时是否值得考虑。

对齐不仅对性能很重要,而且对正确性也很重要。如果数据未正确对齐或访问错误的内存位置,某些体系结构将因处理器陷阱而失败。在其他情况下,对未对齐变量的访问被分解为多次访问和移位(通常在硬件内部,有时通过操作系统陷阱处理程序),从而失去原子性。

建议按大小降序对成员进行排序是为了优化打包/最小化填充所浪费的空间,而不是为了对齐或速度无论您以何种顺序列出成员,都将正确对齐,除非您使用专用杂注(即不可移植的#pragma pack)或关键字请求不一致的布局。尽管总结构大小受到填充的影响,也会影响速度,但通常还有另一种排序是最优的。

为了获得最佳性能,您应该尝试将一起使用的成员放入同一缓存行,并将不同线程访问的成员放入不同的缓存行。有时,这意味着要在跨线程共享变量自己的缓存行中单独获得它需要大量的填充。但这总比虚假分享带来的业绩打击要好。

只是为了增加本的伟大答案:

以稍后在应用程序中访问的相同顺序定义结构成员将减少缓存未命中,并可能提高性能。如果整个结构不适合一级缓存,这将起作用。

另一方面,将成员从最大到最小排序可能会减少总体内存使用量,这在存储小型结构阵列时可能很重要。

让我们假设,对于一个架构(我不太了解它们,我认为默认设置32位gcc就是这样,有人会在评论中纠正我),这个结构:

struct MemoryUnused {
uint8_t val0;
uint16_t val1;
uint8_t val2;
uint16_t val3;
uint8_t val4;
uint32_t val5;
uint8_t val6;
}

在内存中占用20个字节,而这个:

struct MemoryNotLost {
uint32_t val5;
uint16_t val1;
uint16_t val3;
uint8_t val0;
uint8_t val2;
uint8_t val4;
uint8_t val6;
}

需要12个。这是由于填充而丢失的8个字节,而smallers结构的大小增加了67%。对于这样的结构的大阵列,增益将是显著的,并且仅仅因为使用的内存量,将减少缓存未命中的数量。