【问题标题】:Reducing the heap size of a C++ program after large calculation大型计算后减少 C++ 程序的堆大小
【发布时间】:2016-04-05 00:36:48
【问题描述】:

考虑一个基于两个步骤的 MPI 应用程序,我们称之为 loadglobalReduce。只是为了简单起见,软件是这样描述的,但还有很多事情要做,所以它不仅仅是一个 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


【解决方案1】:

那么,在设置了这个问题的上下文之后:有没有办法在 C++ 中手动减小堆大小以真正释放未使用的内存?

这取决于操作系统,但很可能是不可能的。

大多数操作系统都会为您保留从单个进程完成的内存分配,直到该进程完全完成并被终止。

【讨论】:

    【解决方案2】:

    堆是在linux上使用mmap实现的,你需要使用自己的堆,你可以完全dispose和munmap。

    munmap 将释放所需的空间。

    查看boost : pool 中的代码,了解允许您独立管理底层堆的实现。

    根据我的经验,使用自定义分配器管理 std 容器非常困难,因为它们是类派生的,而不是实例派生的。

    【讨论】:

      【解决方案3】:

      共享内存能否解决您的问题(即使您不想共享此内存)? 您可以在“加载”阶段分配一块共享内存,并在计算出“myRankVector”后将其卸载。

      (见 shmget, shmat, shmdt, shmctl( ..., IPC_RMID, .))

      【讨论】:

        猜你喜欢
        • 2017-08-21
        • 2016-04-25
        • 2015-02-13
        • 2010-12-22
        • 1970-01-01
        • 1970-01-01
        • 2020-04-24
        相关资源
        最近更新 更多