【发布时间】:2016-04-05 00:36:48
【问题描述】:
考虑一个基于两个步骤的 MPI 应用程序,我们称之为 load 和 globalReduce。只是为了简单起见,软件是这样描述的,但还有很多事情要做,所以它不仅仅是一个 Map/Reduce 问题。
在 load 步骤期间,每个给定节点中的所有 rank 都排入队列,因此只有一个 rank 可以完全访问节点的 all 内存。之所以这样设计,是因为在加载阶段,有一组大的IO块被读取,都需要在之前在内存中加载一个local reduction 可以发生。我们将把这个局部缩减的结果称为命名变量myRankVector。一旦获得 myRankVector 变量,IO 块就会被释放。变量 myRankVector 本身占用的内存很少,所以在创建过程中节点可以使用 all 内存,完成后排名只需要使用 2-3 GB 即可保存myRankVector.
在节点的globalReduce阶段,预计节点中的所有rank都加载了它们对应的globalReduce。
所以这是我的问题,虽然我确保绝对没有任何内存泄漏(我使用共享指针进行编程,我使用 Valgrind 进行了双重检查等),但我确信即使在所有析构函数已释放 IO 块。当队列中的下一个 rank 开始工作时,它开始像前一个 rank 一样请求大量内存,当然程序会得到 Linux kill 产生“Out of memory: Kill process xxx (xxxxxxxx) score xxxx or牺牲孩子”。很明显为什么会这样,队列中的第二个 rank 想要使用所有内存,但第一个 rank 仍然有一个大堆。
那么,在设置了这个问题的上下文之后:有没有办法在 C++ 中手动减小堆大小以真正释放未使用的内存?
谢谢。
【问题讨论】:
-
可能没有帮助,但您可以 fork/exec 一个子程序来进行大计算,然后它的堆在退出时将被“真正释放”。
-
我们需要查看代码。问题是为什么第二个等级不重用释放的内存。
-
为什么不在每个节点上都有一个进程在所有等级的循环中将:1)获取等级向量,2)启动一个单独的线程,固定到不同的核心,访问等级向量?然后所有主要的内存使用都在同一个进程中,在仍然使用并行性的同时解决您的问题。
-
可能需要检查那些共享指针。你确定工作完成后资源会被释放吗?需要调用 sp.reset() 吗?
-
@gxy,共享指针都被正确销毁了,我在程序上运行了 Valgrind,并且作为常规测试程序的一部分,各个类的所有测试单元都使用 Valgrind 运行。
标签: c++ memory mpi heap-memory