类的对象成员的顺序是否会对性能产生影响?

Poo*_*ria 14 c++ binary performance class object

可能某个类对象的二进制体系结构中的成员的顺序会对使用该类的应用程序的性能产生影响吗?我想知道如果答案是肯定的,如何决定POD成员的顺序,因为程序员通过他们的声明顺序定义了成员的顺序

Pot*_*ter 28

绝对.除非访问限定符介入,否则C++保证内存中对象的顺序与声明顺序相同.

直接相邻的对象更可能位于同一个高速缓存行上,因此一个内存访问将同时获取它们(或从缓存中刷新它们).缓存有效性也可以得到改善,因为其中的有用数据的比例可能更高.简而言之,代码中的空间局部性转换为性能的空间局部性.

此外,正如Jerry在评论中指出的那样,订单可能会影响填充量.通过减小大小来对成员进行排序,这也是通过减少对齐(通常将数组视为其类型的一个元素,将成员结构视为其最对齐的成员).不必要的填充可能会增加结构的总大小,从而导致更高的内存流量.

C++03§9/ 12:

声明没有插入访问说明符的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址.由访问说明符分隔的非静态数据成员的分配顺序未指定(11.1).实施对齐要求可能导致两个相邻成员不能立即分配; 因此,可能需要空间来管理虚拟功能(10.3)和虚拟基类(10.1).

  • @Pooria:通常情况下,如果你有一个比其他成员使用更多的成员,那就把它放在第一位(间接通常比带有偏移的间接更快).如果您有(几乎)总是一起使用的成员,请将它们物理地保持在一起.除此之外,您通常只需减小大小以减少填充. (4认同)
  • 哇,我没有意识到这一点,但是在问题发布后我发布了这个答案112*秒*! (2认同)

val*_*ldo 7

绝对同意Potatoswatter.但是,应该再添加一个关于CPU缓存行的要点.

如果您的应用程序是多线程的并且不同的线程读/写您的结构成员 - 确保这些成员不在同一个缓存行中非常重要.

关键是每当线程修改在其他CPU中缓存的内存地址时 - 该CPU立即使包含该地址的缓存行无效.因此,不正当的成员订单可能导致不合理的缓存失效和性能下降.


Aru*_*run 5

除了缓存行相关答案中描述的运行时性能之外,我认为还应该考虑内存性能,即类对象的大小。

由于填充,类对象的大小取决于成员变量声明的顺序。

以下声明可能需要 12 个字节

class foo {
    char c1;
    int  i;
    char c2;
}
Run Code Online (Sandbox Code Playgroud)

然而,对成员声明的顺序进行简单的重新排序后,以下内容可能会占用 8 个字节

class bar {
    int  i;
    char c1;
    char c2;
}
Run Code Online (Sandbox Code Playgroud)

在与 4 字节字对齐的机器中:

sizeof( foo ) = 12
Run Code Online (Sandbox Code Playgroud)

sizeof( bar ) = 8
Run Code Online (Sandbox Code Playgroud)