对齐对C++ 11的性能是否真的重要?

use*_*311 38 c++ memory-alignment c++11

对齐对C++ 11的性能是否真的重要?

在Stroustrup的书中有一条建议,要求从最大到最小的结构中对成员进行排序.但我想知道是否有人进行了测量,以确定是否会产生任何影响,并且在编写代码时是否值得考虑.

Ben*_*igt 85

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

按大小降序对成员进行排序的建议是通过填充浪费最佳包装/最小空间,而不是对齐或速度. 无论您将它们列在哪个顺序,成员都将正确对齐,除非您使用专门的编译指示(即非可移植的#pragma pack)或关键字请求不符合的布局.虽然总结构大小受填充影响并且还影响速度,但通常还有另一种最佳排序.

为了获得最佳性能,您应该尝试将一起使用的成员放在同一个缓存行中,并将不同线程访问的成员放入不同的缓存行中.有时,这意味着需要大量填充才能在其自己的缓存行中单独获取跨线程共享变量.但这比通过虚假共享获得性能更好.

  • 也许解释为什么排序有所帮助是有益的:编译器将尊重对齐规则,但也必须尊重成员顺序.如果按大小排序,编译器需要插入较少的填充.这是因为在实践中按大小排序相当于按对齐限制进行排序(这是你实际上应该做的事情 - 一个`char [53]`应该去最后) (3认同)
  • 这是一个很好的答案 (2认同)

Dar*_*usz 9

只是为了补充Ben的好答案:

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

另一方面,将成员从最大到最小排序可以减少总体内存使用,这在存储小结构阵列时可能是重要的.

让我们假设对于一个架构(我不太了解它们,我认为默认设置是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;
}
Run Code Online (Sandbox Code Playgroud)

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

struct MemoryNotLost {
  uint32_t val5;
  uint16_t val1;
  uint16_t val3;
  uint8_t val0;
  uint8_t val2;
  uint8_t val4;
  uint8_t val6;
}
Run Code Online (Sandbox Code Playgroud)

将占用12.由于填充而丢失了8个字节,并且smaller结构的大小增加了67%.对于大量这样的结构,增益将是显着的,并且仅仅因为使用的存储器量将减少高速缓存未命中的数量.

  • @cmaster首先,问题是理论上的.其次,我们在结构中使用多个char []来在前端存储用户输入数据 - 我们可能不会为此感到自豪,但事实就是如此.指向多个长字符串的指针也一样糟糕.第三 - 这就是重点,整体规模可以通过订购减少.第四 - 我不明白你在这里讲的是什么.当然不是我的帖子. (2认同)