c ++替代实现,以避免在RAM和SWAP内存之间切换

时间:2014-05-30 10:15:57

标签: c++ memory memory-management heap

我有一个程序,它使用动态编程来计算一些信息。问题是,理论上使用的内存呈指数增长。我使用的一些过滤器限制了这个空间,但是对于大输入,它们也无法避免我的程序耗尽RAM - 内存

该程序在4个线程上运行。当我用一个非常大的输入运行它时,我注意到,在某些时候程序开始使用交换内存,因为我的RAM不够大。这样做的结果是,我的 CPU使用率从大约380%降低到15%或更低

只有一个变量使用内存,即以下数据结构:

使用CLN library修改(添加的类型):

class My_Map {

    typedef std::pair<double,short> key;
    typedef cln::cl_I value;

public: 
    tbb::concurrent_hash_map<key,value>* map;

    My_Map()  { map = new tbb::concurrent_hash_map<myType>(); }
    ~My_Map() { delete map; }

    //some functions for operations on the map
};

在我的主程序中,我将此数据结构用作全局变量:

My_Map* container = new My_Map();

问题:

有没有办法避免SWAP和RAM之间的内存转移?我认为将所有记忆推到Heap会有所帮助,但似乎没有。所以我不知道是否有可能完全使用交换内存或其他东西。只是这种内存的转移花费了很多时间。 CPU使用率急剧下降。

2 个答案:

答案 0 :(得分:3)

如果你有1千兆字节的RAM并且你有一个耗尽2 Gb RAM的程序,那么你将不得不找到其他地方来存储多余的数据..显然。默认的操作系统方式是交换,但另一种方法是使用内存映射文件管理自己的“交换”。

您打开一个文件并在其中分配一个虚拟内存块,然后将该文件的页面放入RAM中进行处理。操作系统在很大程度上为你管理这个,但你应该考虑一下你的内存使用情况,这样就不要试图在内存中保持访问相同的块,如果可以的话。

在Windows上使用CreateFileMapping(),在Linux上使用mmap(),在Mac上使用mmap()

答案 1 :(得分:3)

操作系统正常工作 - 在交换时它不会区分堆栈和堆 - 它会向您发送任何您不使用的内容,并加载您要求的任何内容。

您可以尝试一些事项:

  • 考虑myType是否可以缩小 - 例如使用int8_t或甚至宽度适当的位域而不是int,使用指向池化字符串而不是最坏情况长度字符数组的指针,使用偏移到数组中,它们比指针小。如果你告诉我们这种类型,我们可以提出建议。

    • 考虑你的分页 - 如果你在一个内存页面上有很多对象(可能是4k),如果使用其中任何一个,他们将需要留在内存中,所以尝试获取将在周围使用的对象同一时间到同一个内存页面 - 这可能涉及散列到相关myType对象的小数组,或者如果可能的话甚至将所有数据移动到打包数组中(无论如何二进制搜索都可以很快)。天真使用的哈希表倾向于剥夺内存,因为类似的对象放在完全不相关的桶中。

    • 使用压缩进行序列化/反序列化是可能的:您可以主动将它们序列化为更紧凑的形式,然后仅在需要时对它们进行反序列化,而不是让操作系统更换完全的myType内存

      < / LI>
  • 考虑您是否需要同时处理所有数据...如果您可以批量处理工作,以便获得所有&#34; A组&#34;使用更少的内存,然后你可以继续前进到&#34; B组&#34;


更新现在您已发布实际数据类型......

可悲的是,使用short可能没什么用,因为sizeof key无论如何都需要为double的对齐;如果你不需要精确度,你可以考虑float?另一个选择是创建一个单独的地图数组......

tbb::concurrent_hash_map<double,value> map[65536];

然后您可以索引到map[my_short][my_double]。它可能更好或更糟,但很容易尝试,所以你也可以做基准....

cl_I进行2分钟的挖掘表明存储在union中的数据 - 大概是word用于小值,必要时用于其中一个指针。这看起来像一个很好的设计 - 很难改进。

如果数字往往会重复很多(一个很大的if),你可以尝试例如保持大cl_I s的注册表与双向映射到您My_Map::map中存储的压缩整数ID - 虽然繁琐。要解释一下,比如说你得到987123498723489 - 你push_back上的vector<cl_I>,然后hash_map<cl_I, int>设置[987123498723489到该索引(即vector.size() - 1)。在遇到新号码时继续前进。您始终可以使用int中的直接索引从cl_I ID映射回vector,另一种方式是O(1)分摊的哈希表查找。