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

17

一个类的二进制对象的成员顺序是否会影响使用该类的应用程序的性能?若是的话,我想知道如何决定POD的成员顺序,因为程序员通过它们声明的顺序来定义成员的顺序。

3个回答

31
当没有访问限定符时,C++保证对象在内存中的顺序与声明顺序相同。直接相邻的对象更可能在同一个缓存行中,因此一次内存访问将获取它们两个(或将它们两个从缓存中刷新)。代码中的空间局部性有助于提高缓存效率,因为其中有用数据的比例可能更高。此外,排序还可能影响填充量的大小。按照成员大小递减的顺序对成员进行排序,这也是按递减对齐方式排序的顺序(通常将数组视为其类型的一个元素,将成员结构视为其最对齐的成员)。不必要的填充可能会增加结构体的总大小,导致更高的内存流量。根据C++03 §9/12的规定,未经访问限定符指定的非静态数据成员在类对象内部分配,以便后面的成员具有更高的地址。通过访问限定符分隔的非静态数据成员的分配顺序是未指定的。实现对齐要求可能会导致两个相邻的成员不立即相互分配;因此,可能需要为管理虚函数(10.3)和虚基类(10.1)而保留空间。

3
哇,我没有意识到,在问题发布后112秒就回答了这个问题! - Potatoswatter
也许大小也很重要。由于x86(和可能许多其他)处理器具有用于索引寄存器的内存访问的特殊操作码,具有1、2、4或8字节大小的对象数组将被更快地访问。 - ruslik
那么在处理POD类型时,由于顺序是由程序员定义的,有人如何决定哪个顺序对性能最好? - Pooria
4
通常情况下,如果您有一个成员比其他成员使用频率更高,请将其放在第一位(间接引用通常比带偏移量的间接引用更快)。如果有几个成员经常会(几乎总是)同时使用,请将它们物理上保持在一起。除此之外,通常只需按降序排序以最小化填充。 - Jerry Coffin

7
完全同意Potatoswatter的观点。然而,还有一个关于CPU缓存行的要点需要补充。
如果您的应用程序是多线程的,并且不同的线程读/写结构体的成员 - 确保这些成员不在同一缓存行非常重要。
问题在于,每当一个线程修改了其他CPU中缓存的内存地址时,该CPU立即使包含该地址的缓存行无效。因此,不适当的成员顺序可能会导致不合理的缓存失效和性能下降。

5
除了与缓存行相关的答案中所描述的运行时性能外,我认为人们还应该考虑内存性能,即类对象的大小。
由于填充的原因,类对象的大小取决于成员变量声明的顺序。
以下声明可能需要12个字节。
class foo {
    char c1;
    int  i;
    char c2;
}

然而,只需简单地重新排列成员声明的顺序,以下内容可能只占用8个字节。
class bar {
    int  i;
    char c1;
    char c2;
}

在按4字节对齐的机器上:

sizeof( foo ) = 12

但是
sizeof( bar ) = 8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接