C++ (C+;+;)寻找减少内存使用的技巧

C++ (C+;+;)寻找减少内存使用的技巧,c++,memory-management,C++,Memory Management,我有一个非常严格的内存限制问题。我是一个CPP极客,我想减少我的内存使用。请给我一些提示 我的一个朋友建议从结构中取出函数。 例如,不使用: struct node{ int f() {} } 他建议我使用: int f(node x) {} 这真的有用吗 注意:我有很多我的结构副本 以下是更多信息: 我正在为一个在线评委的练习题编写一个片段树。我在结构中得到树节点。my struct具有以下变量: int start; int end; bool flag;

我有一个非常严格的内存限制问题。我是一个CPP极客,我想减少我的内存使用。请给我一些提示


我的一个朋友建议从结构中取出函数。 例如,不使用:

struct node{
   int f()
   {}
}
他建议我使用:

int f(node x)
{}
这真的有用吗

注意:我有很多我的结构副本


以下是更多信息:

我正在为一个在线评委的练习题编写一个片段树。我在结构中得到树节点。my struct具有以下变量:

  int start;
  int end;
  bool flag;
  node* left;
  node* right;

内存限制为16 MB,我使用的是16.38 MB。

不,常规成员函数不会使类或结构变大。引入虚拟函数可能(在许多平台上)会添加指向该类的指针。在x86上,这会将大小增加四个字节。不过,添加虚拟函数时不需要更多内存——一个指针就足够了。类或结构类型的大小从不为零(无论它是否有任何成员变量或虚拟函数)。这是为了确保每个实例都占用自己的内存空间(,第9.0.3节)。

您可以使用编译标志进行一些优化。如果您使用的是g++,则可以使用:-O2进行测试

关于这个主题,有很多好的线索:


,在我看来,减少内存的最好方法是考虑算法空间的兼容性,而不是做精细的代码优化。重新考虑动态编程表、不必要的副本,通常是内存效率方面有问题的任何东西。另外,只要不再需要内存资源,就尽量尽早释放它们。

根据你问题的潜台词,我猜大部分内存使用是数据,而不是代码。以下是一些提示:

  • 如果您的数据范围有限,请充分利用它。如果整数的范围是-128到127,则使用
    char
    而不是int,如果是0到255,则使用
    unsigned char
    。同样,对于-32768..32767和0..65535的范围,使用
    int16\u t
    uint16\u t
  • 重新排列结构元素,因此较大的项首先出现,这样数据对齐不会在结构中间留下死区。您通常也可以通过编译器选项来控制填充,但最好首先使布局优化
  • 使用开销不大的容器。例如,使用
    向量
    代替
    列表
    。使用而不是
    std::vector
    包含
    shared\u ptr
  • 避免虚拟方法。添加到结构或类的第一个虚拟方法将向vtable添加隐藏指针

这两种可能性完全不同:

  • 在第一个函数中,
    f()
    节点的成员函数
  • 在第二个函数中,
    f()
    是一个自由函数(或命名空间作用域)。(还要注意,两个
    f()
    的签名是不同的。)
现在请注意,在第一种样式中,
f()
是一个
inline
成员函数。在类主体内定义成员函数使其内联。虽然内联没有得到保证,但它只是对编译器的一个提示。对于具有小实体的函数,最好将它们内联,因为这样可以避免过度调用函数。然而,我从来没有看到这是一个成功或失败的因素

如果您不希望或
f()
不适合内联,则应在类主体之外(可能在.cpp文件中)将其定义为:

如果代码中存在内存使用问题,那么上述主题很可能不相关。探索以下内容可能会给您一些提示

  • 查找程序中所有类的大小。使用
    sizeof
    查找此信息,例如sizeof(节点)
  • 查找程序正在创建的每个类的最大对象数
  • 使用上述两系列信息,估计程序在最坏情况下的内存使用情况

    最坏情况下的内存使用率=n1*sizeof(node1)+n2*sizeof(node2)+

如果上述数字过高,则您有以下选择:

  • 减少类的最大实例数。这可能是不可能的,因为这取决于程序的输入,而这超出了您的控制范围
  • 减少每个类的大小。不过这是在你的控制之下

如何减少班级规模?尝试将类成员紧凑地打包以避免出现错误。

正如其他人所说,拥有方法不会增加结构的大小,除非其中一个是虚拟的

您可以使用位字段有效地压缩数据(这对于布尔值…)尤其有效。此外,您可以使用索引而不是指针来保存一些字节

请记住,要将节点分配成大块,而不是单独分配(例如,使用new[]一次,而不是常规的new多次),以避免内存管理开销

如果不需要节点指针提供的全部灵活性,可以减少或消除它们。例如,heapsort总是有一个接近完整的二叉树,因此标准实现使用隐式树,它根本不需要任何指针


最重要的是,找到一个不同的算法可能会完全改变游戏…

对于最后一个示例(树),您可以使用一个巧妙的XOR hack,将两个节点指针替换为一个节点指针,如前所述。但是,这仅在以正确的顺序遍历树时有效。显然,这会损害代码的可读性,因此应该是最后的手段。

您的程序是做什么的?它使用什么算法?很难笼统地谈论优化。如果您在linux上,那么您可以使用valgrind/massif来查看您的h
 int node::f() { /* stuff here */ }