在C++中优化类实例的内存布局

6

将应用程序从32位升级到64位会增加指针大小和对象的内存占用。

我正在寻找尽可能减少对象内存占用的方法。对于POD结构体,我会转储结构体的内存布局,以确定如何打包成员并减少编译器填充。

是否有一种方法可以了解非POD对象(如类实例)的内存布局?如何实现类对象的打包类似的操作?

谢谢, 丹


1
通常会有特定于编译器的标志和编译指示,重新排序字段可能会产生影响。然而,所有这些都可能会影响性能和互操作性。 - sehe
@dbbd 顺便问一下,为什么你担心64位架构中的进程内存大小?64位架构可以支持巨大的虚拟内存大小,不像32位架构。 - weima
你也可以使用不同的打包选项构建程序,并比较两种情况下的内存消耗(打印sizeof或运行一些真实测试)。这可能会帮助你确定是否值得继续深入研究。 - user396672
抱歉,我在 Linux/CentOS 64 位架构上使用 gcc。 - dbbd
从技术角度来看,POD类和非POD类/结构体之间没有区别。它们都是结构体。 - valdo
显示剩余3条评论
4个回答

6
你可以使用GCC的-Wpadded选项来指示哪些地方添加了填充,然后根据这些信息进行重新排序,在某些情况下可以减小大小。
强制紧缩数据在内存中的表示不是一个好主意。

1

我不知道特定的非 POD 对象数据(即 vtable),尽管我认为这由指针大小所决定。 无论如何,您可以通过编译器指令 #pragma pack 来控制成员的对齐方式,该指令被 GCCVisual Studio 支持。

您还可以阅读美妙的 Agner Fog C++ optimize guide 第 7.18 段:

类或结构体的数据成员在创建类或结构体实例时以声明的顺序依次存储。将数据组织成类或结构体不会产生性能损失。访问类或结构体对象的数据成员所需的时间与访问简单变量所需的时间相同。大多数编译器将对齐数据成员以优化访问以获得更好的性能。


0
关于非POD对象,我认为你应该更多地了解vTable、虚函数、虚继承等知识,以了解哪些因素影响类或对象的大小。实际上,类对齐会产生填充,类成员对齐只是影响类大小的因素之一。
以下是一些相关网站,我认为它们可能对你有所帮助:
  1. 确定类对象的大小:http://www.cprogramming.com/tutorial/size_of_class_object.html

  2. 内存布局:http://www.phpcompiler.org/articles/virtualinheritance.html

此外,如果你使用MVSC,你可以通过像这样的命令“-d1reportAllClassLayout”来转储解决方案中所有类的内存布局。
cl -d1reportAllClassLayout main.cpp

0

经验法则:从大到小排列;这样可以在元素大小为2的幂时实现完美对齐,否则可以进行手动优化。

请注意,即使CPU能够从违规中恢复过来,适当的对齐通常对速度至关重要。虽然x86和(据我所知)x64 CPU会通过第二次读取来处理不对齐的访问,但由于浪费在不对齐读取上的时间通常比由于较小的工作集而节省的时间要多得多。因此,只有在对多个CPU运行比较时才会“紧密打包”。

对于非POD类型,您需要检查sizeof(element)
(如果有大量对象,我可能会使用简单的解析器生成C++代码以转储这些大小)

或者,PVS-Studio分析了结构体大小并提供了重新排序建议。我还没有考虑过它们,但您可以使用评估来确定它是否适合您。


重新排序成员并不是一个容易的选择,因为有很多编码器/解码器和其他RPC相关的东西,这总是一个大头痛。此外,对于一个IO绑定的应用程序,CPU性能并不重要。我更喜欢牺牲CPU来节省内存,而不是为了这种类型的IO绑定应用程序获得性能而失去内存。 - dbbd

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