关于c ++:为什么Visual Studio不优化结构以获得最佳内存使用?

How come Visual Studio does not optimize structs for best memory usage?

本问题已经有最佳答案,请猛点这里访问。

我的问题是,为什么Visual Studio 2012编译器不自动重新排序结构成员以获得最佳内存利用率?编译器似乎按照结构定义中声明的顺序存储成员,并根据成员对齐的需要使用一些空填充。在可能的情况下,重新排序似乎比填充更适合对齐成员。它必须按声明顺序存储在内存中吗?

相关细节如下:

我有一个结构,它表示一个大数组中的单个元素。元素有许多成员,一些32位,一些64位。我调到了默认的结构成员对齐以获得最佳性能。

我在调试模式下研究内存,发现有很大一部分内存被浪费了。我追踪到了学生们在记忆中是如何排列的这个问题。我知道32位成员必须在dword边界上对齐才能获得最佳性能,显然64位成员必须在qword边界上对齐(我本以为dword边界足够)。

我可以通过更改在结构定义中列出成员的顺序来解决这个问题。我确保尽可能地将2个32位成员放在一起,这样就不需要填充就可以在Qword边界上启动下一个64位成员。


这是C++标准,编译器不能修改字段的顺序,可能是因为程序员可能希望通过指向第一个字段的字段来访问字段。如果您需要自己重新排序,请看这篇文章。

第9.2.13节:

Nonstatic data members of a (non-union) class with the same access
control (Clause 11) are allocated so that later members have higher
addresses within a class object. The order of allocation of non-static
data members with different access control is unspecified (Clause 11).
Implementation alignment requirements might cause two adjacent members
not to be allocated immediately after each other; so might
requirements for space for managing virtual functions (10.3) and
virtual base classes (10.1).


标准布局结构或类中的数据必须保证一定的布局。另外,如果有另一个标准的布局结构或类是第一个的前缀,那么您必须能够像其他结构一样重新解释一个结构,并且公共前缀必须一致。

这基本上强制标准布局结构的内存顺序与声明它们的顺序相同。

这类似于C在结构布局方面的要求,如本文所述。

现在,在C++中,对于非标准布局结构有一定的自由度。

[表达式rel]/3子点3:

If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member compares greater provided the two members have the same access control (Clause 11) and provided their class is not a union.

元素的顺序必须在公共/私有/受保护的访问控制域中维护。元素之间的空间可以以几乎任意的方式添加。

这意味着您可以知道&this->x大于或小于&this->y,这是一些程序员可能使用的。

根据假设规则,如果没有人获取此类数据的地址,编译器可以对其重新排序。在通常的编译模型中很难证明这一点。

根据我的经验,msvc中元素之间的间距与普通旧数据结构中的间距相匹配,除非是通过虚拟游戏进行继承。布局兼容性(超出标准)对于稳定的ABI很重要,使用一个版本的编译器编译的代码最好在另一个版本中工作。打破这种局面是有代价的。

C++程序员可以根据需要重新排序数据结构,VisualStudio提供EDCOX1×0秒来改变结构打包规则,所以如果你真的需要最后一点的性能,你可以得到它。

您甚至可以编写一个类似于tuple的数据结构,以确保在需要时进行最佳打包。(我不依赖std::tuple,因为它没有包装保证)


我怀疑这是重叠需求的交叉点。

  • C和C++中相同POD结构的布局应该是二进制兼容的。(我不知道这是否是标准所要求的,但大多数编译器供应商可能会优先考虑它,因为许多现有的代码都依赖于它。)
  • C++中的结构和类实际上是相同的,除了默认可见性。
  • 类的数据成员按声明的顺序构造,并按相反的顺序销毁。
  • 如果编译器要对数据成员重新排序以获得更好的对齐和/或更紧密的打包,这是否会更改构造/破坏顺序的顺序?不,这会破坏很多依赖RAII的代码。但现在构造期间的内存访问顺序较低,这实际上可能是一种混乱,这取决于缓存行为、结构的大小以及构造这些结构的频率。

    您可以认为,这些担忧不适用于POD结构,但需求1和2表示,C++编译器必须以与类相同的方式布局POD结构(反之亦然)。


    如果没有EDCOX1×0的S,则内存不会被C++打包,并且不会重新排序,因为语言保证了与代码一致的布局。想象一下会造成的破坏——将结构映射到文件(内存映射文件)或硬件将永远不会工作。

    为了获得对类或结构的布局的感觉,VisualC++提供了一个未记录的命令行参数EDCOX1(1),它将为您绘制类/结构的内存布局的ASCII艺术图,包括所有成员、基成员和VTABLE。例如,如果有一个名为foo的类,请将/d1reportSingleClassLayoutfoo添加到编译器命令行中。