避免在RAM和SWAP内存之间切换的可选实现
c++ Alternative implementation to avoid shifting between RAM and SWAP memory
我有一个程序,使用动态规划来计算一些信息。问题是,理论上使用的内存呈指数级增长。我使用的一些过滤器限制了这个空间,但是对于大的输入,它们也不能避免我的程序耗尽RAM -内存。
程序在4个线程上运行。当我用一个非常大的输入运行它时,我注意到,在某些时候,程序开始使用交换内存,因为我的RAM不够大。这样做的结果是,我的 cpu使用率从大约380%下降到15%或更低。
只有一个变量使用内存,它是以下数据结构:
使用CLN库编辑(添加类型):
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
会有帮助,但似乎没有。所以我不知道是否有可能充分利用交换内存或其他东西。仅仅是这种记忆的转移就花费了很多时间。
如果你有1g的RAM,而你的程序使用了2gb的RAM,那么你将不得不找到其他地方存储多余的数据。很明显。默认的操作系统方式是交换,但另一种选择是通过使用内存映射文件来管理您自己的"交换"。
您打开一个文件并在其中分配一个虚拟内存块,然后将文件的页面放入RAM中进行处理。操作系统在很大程度上为你管理这些,但是你应该考虑你的内存使用,所以如果可以的话,不要试图访问相同的块。
在Windows上使用CreateFileMapping(),在Linux上使用mmap(),在Mac上使用mmap()。
操作系统工作正常-它在交换时不会区分堆栈和堆-它会将您似乎没有使用的内容分页并加载您请求的内容。
有几件事你可以试试:
-
考虑
myType
是否可以更小-例如使用int8_t
或甚至宽度适当的位域代替int
,使用指针池字符串代替最坏情况长度字符数组,使用偏移量到数组中,它们比指针小等。如果你给我们看看型号,也许我们可以提出建议。-
考虑您的分页—如果您在一个内存页上有许多对象(可能是4k),如果其中任何一个对象正在使用,它们将需要留在内存中,因此尝试将大约在同一时间使用的对象放在同一内存页上—这可能涉及到相关
myType
对象的小数组的散列,或者甚至将所有数据移动到一个打包数组中(如果可能的话,二进制搜索可以非常快)。天真地使用哈希表往往会消耗内存,因为相似的对象被放在完全不相关的桶中。 -
序列化/反序列化与压缩是一种可能性:而不是让操作系统交换出完整的myType内存,您可以主动将它们序列化成更紧凑的形式,然后只在需要时才反序列化
-
-
考虑是否需要同时处理所有数据…如果你能批量处理工作,用更少的内存完成所有的"a组",那么你就可以转移到"B组"
更新现在你已经发布了你的实际数据类型…
遗憾的是,使用short
可能没有多大帮助,因为sizeof key
无论如何都需要16来对齐double
;如果不需要精度,可以考虑float
?另一种选择是创建一个单独的映射数组…
tbb::concurrent_hash_map<double,value> map[65536];
你可以索引到map[my_short][my_double]
。它可能更好或更差,但很容易尝试,所以您不妨对....
对于cl_I
, 2分钟的挖掘表明数据存储在联合中-大概word
用于小值和必要时的一个指针…这个设计看起来不错,很难再改进了。
如果数字倾向于重复很多(一个大的如果),你可以尝试例如保持一个大cl_I
的注册表,并将其双向映射到打包的整数id,你将存储在My_Map::map
中-虽然很繁琐。为了解释,假设你得到987123498723489 -你在vector<cl_I>
上push_back
它,然后在hash_map<cl_I, int>
中将[987123498723489
设置为该索引(即vector.size() - 1
)。当遇到新的数字时,继续前进。您总是可以使用vector
中的直接索引将int
id映射回cl_I
,另一种方法是使用O(1)
平摊哈希表查找。
- 比较器的两个实现之间的差异
- C++:调用运算符和调用其实现之间有区别吗
- C++ 和 Python 实现之间的不同伪随机数
- 有没有办法根据模板参数的类型在不同的类实现之间进行选择
- 可能的std ::前向实现之间的区别
- 原子衰落实现之间的差异
- STD ::正向实现之间的区别
- 链接列表C 类,这两个添加节点实现之间的差异是什么?
- 优先级队列使用堆 - JavaScript和C 实现之间的差异
- 以下 C++ 结构实现之间的区别
- 使用指针和使用静态对象实现单例实现之间的区别
- 作用域在两个类实现之间不完全独立
- c++中两种形式的专业化模板实现之间的区别是什么
- 为什么我看到两个blowfish实现之间不一致
- 来自 vtable 的未定义符号是否意味着接口和实现之间存在错误
- 使用函数指针在函数实现之间切换
- STL队列(OR堆栈)的deque和链表(+vector)实现之间有什么区别
- 函数原型和C++中的函数实现之间的区别是什么
- 不同实现之间的随机输出不同
- c++提倡类定义和类实现之间的分离,但JAVA没有