我有一个程序,它使用动态编程来计算一些信息。问题是,理论上使用的内存呈指数增长。我使用的一些过滤器限制了这个空间,但是对于大输入,它们也无法避免我的程序耗尽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使用率急剧下降。
答案 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)
分摊的哈希表查找。