减少利用大矢量的 c++ 程序的内存占用
Reducing memory footprint of c++ program utilising large vectors
在扩大我交给一个自编码程序的问题大小时,我开始遇到Linux的OOM杀手锏。Valgrind(在CPU上运行时(和cuda-memcheck(在GPU上运行时(都不会报告任何内存泄漏。在迭代内部循环时,内存使用量不断扩大,而我显式清除了在此循环结束时保存最大数据块的向量。如何确保这种内存占用会消失?
执行了内存泄漏检查,所有内存泄漏都已修复。尽管如此,内存不足错误仍然会杀死程序(通过 OOM Killer(。手动监视内存消耗显示内存利用率增加,即使在显式清除包含数据的向量后也是如此。
要知道的关键是有三个嵌套循环,一个外部包含手头的子问题。中间循环在蒙特卡洛试验上循环,内部循环运行试验内所需的一些顺序过程。伪代码如下所示:
std::vector<object*> sub_problems;
sub_problems.push_back(retrieved_subproblem_from_database);
for(int sub_problem_index = 0; sub_problem_index < sub_problems.size(); ++sub_problem_index){
std::vector< std::vector<float> > mc_results(100000, std::vector<float>(5, 0.0));
for(int mc_trial = 0; mc_trial < 100000; ++mc_trial){
for(int sequential_process_index = 0; sequential_process_index < 5; ++sequential_process_index){
mc_results[mc_trial][sequential_process_index] = specific_result;
}
}
sub_problems[sub_problem_index]->storeResultsInObject(mc_results);
// Do some other things
sub_problems[sub_problem_index]->deleteMCResults();
}
删除MCResults如下所示:
bool deleteMCResults() {
for (int i = 0; i < asset_values.size(); ++i){
object_mc_results[i].clear();
object_mc_results[i].shrink_to_fit();
}
object_mc_results.clear();
object_mc_results.shrink_to_fit();
return true;
}
如何确保内存消耗完全依赖于中间循环和内部循环而不是外部循环?从理论上讲,第二个、第三个和第四个等可以使用与第一次迭代完全相同的内存空间/地址。
也许我从字面上阅读了您的伪代码,但看起来您有两个mc_results
变量,一个在for
循环中声明,另一个是deleteMCResults
正在访问的。
无论如何,对于如何调试它,我有两个建议。 首先,与其让 OOM 杀手级攻击(这需要很长时间、不可预测并且可能会杀死重要的东西(,不如使用ulimit -v
来限制进程大小。 将其设置为合理的值,例如 1000000(约 1GB(,并努力将您的进程保持在该范围内。
其次,开始删除或注释掉除程序中分配和释放内存的部分之外的所有内容。 要么你会找到你的罪魁祸首,要么你会制作一个足够小的程序来完整地发布。
deleteMCResults()
可以写得简单得多。
void deleteMCResults() {
decltype(object_mc_results) empty;
std::swap(object_mc_results, empty);
}
但在这种情况下,我想知道你是否真的想释放内存。正如您所说,迭代可以重复使用相同的内存,因此也许您应该将deleteMCResults()
替换为returnMCResultsMemory()
.然后将mc_results
声明提升到循环之外,并在returnMCResultsMemory()
返回后将其值重置为 5.0。
有一件事可以很容易地从你显示的代码中改进。但是,它确实不够充分,也不够精确,无法进行全面分析。提取相关示例([mcve](并可能要求对 codereview.stackexchange.com 进行审查可能会改善结果。
可以做的简单事情是用五个浮点数的数组替换五个浮点数的内部向量。每个向量(在典型实现中(由三个指针组成,指向分配内存的开始和结束,另一个指针用于标记使用量。实际存储需要单独的分配,这反过来又会产生一些开销(以及访问数据时的性能开销,关键字"引用位置"(。这三个指针在普通的 64 位计算机上需要 24 个八位字节。与五个浮点数相比,这些浮点数只需要 20 个八位字节。即使这些浮点数被填充到 24 个八位字节,您仍然可以从省略单独的分配中受益。
为了尝试这个,只需用std::array
(https://en.cppreference.com/w/cpp/container/array(替换内部向量。很有可能您不必更改太多代码、原始数组、std::array
和std::vector
具有非常相似的接口。
- Mongodb c++驱动程序:如何查询元素的数组
- C++,系统无法执行指定的程序
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 重载操作程序时出错>>用于类中的字符串 memebr
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 试图在visual studio上用C++创建一个桌面应用程序
- 模板元程序查找相似的连续类型名称
- FFmpeg:制作一个应用程序比直接使用ffmepg更好吗
- 如何通过cpp程序运行shell脚本
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- IPC使用多个管道和分支进程来运行Python程序
- 如何将c++程序的一些输出传递给shell,以便在shell中使用
- 使用C++程序合并排序没有得到正确的输出
- 基于boost的程序的静态链接——zlib问题
- 程序崩溃并显示"std::out_of_range"错误
- 在C应用程序中运行C++(带有STL)函数
- 使用mongocxx驱动程序时包含头文件问题
- 如何在c++程序中找到函数的地址