【问题标题】:Deallocated Heap Not Being Reclaimed?释放的堆没有被回收?
【发布时间】:2016-01-20 17:34:32
【问题描述】:

我有一个 C++ 进程,它摄取大块数据并将它们存储在内存中。存储阵列包含大约 10 GB 的数据,划分为 4 MB 的块。当新数据到达时,它会创建一个新块,然后如果旧块已满,则删除它。此过程每 10 - 60 秒循环一次完整的循环缓冲区。我们在 x86_64 RH5 和 RH6 上运行,并使用 Intel 14 编译器进行编译。

我们看到了一个问题,即整个进程的内存使用量会随着时间的推移而增长,直到操作系统内存不足并最终导致机器死机。我们一直在寻找内存泄漏并通过 TotalView 运行进程,试图确定内存的去向,但没有看到任何报告的泄漏。

在总视图生成的堆报告中,我们看到为存储的数据分配了 10GB 的内存,但我们也看到了 4+GB 的“释放”内存。查看堆显示,我们的堆看起来非常碎片化。会有一大块“已分配”内存穿插着大块“已释放”内存。

  • 我的进程已释放但操作系统未回收的“已释放”内存是否合理认为这可能是我们的内存“泄漏”的来源?

  • 如果是这样,我如何让操作系统回收内存?

  • 我们是否需要重新设计流程以重用丢弃的数据块,而不是依赖操作系统为我们进行内存管理?

【问题讨论】:

  • 如果内存消耗不断增加,这通常意味着您new 占用了一些内存,而永远不会delete 它。您是否尝试过使用 gdb 之类的东西?
  • 我们一直在运行 TotalView 提供的内存分析和泄漏检测工具,它没有报告任何未删除的消息。我还将 cerr 放入数据块的构造函数和析构函数中,以验证我们没有丢失任何数据。
  • 您在编写什么样的 C++ 应用程序?一台数据服务器,还是一台 HPC(数值计算)服务器?它运行多长时间(几小时或几个月)?
  • 我认为没有避免碎片的“最佳”方法,但如果有许多大小相同的块,池化分配器可能是个好主意。
  • @mjr:您的问题不是通用的 C++ 问题(如果您没有真正的泄漏),而是取决于(1)您的操作系统,(2)您的 C++ 实现,以及(3)可能您的 C 实现可能会为 C++ 实现提供 mallocfree。没有这 2 或 3 个参数,这个问题是不完整的,无法回答。

标签: c++ memory-management memory-leaks


【解决方案1】:

我猜(希望你也是)你在 Linux 上(如果将你的代码移植到 Linux 是可行的,考虑一下,因为 Linux 有很好的工具来解决这些问题)。

然后:

以上内容将帮助您捕获一些剩余的memory leaks。准备好在他们身上花费数周时间。您可能需要禁用ASLR,并且应该了解gdb 观察点。

您也可以考虑使用Boehm's conservative garbage collector。请参阅 this 以在标准 C++ containers 中使用它。如果您确实使用了 Boehm 的 GC,那么您最好在程序中的几乎所有地方都使用它...

可能会发生真正的fragmentation(即使您确定避免了内存泄漏,并且已经检查过,例如使用valgrind),尤其是对于长期存在的进程。在这种情况下,您可能会考虑拥有自己的application checkpointing 设施(这对于重新启动长期计算也很有用)。如果你有足够早的考虑(检查点应该是一个早期的架构设计决策!)你可以偶尔(例如每小时)检查一次你的状态到磁盘并重新启动一个新的进程。这可能是一个很好的内存压缩策略。

您可以(但我不一定推荐)在操作系统virtual address space 上编写自己的内存分配器,更改mmap(2) 之类的原语(可能使用MAP_HUGETLB ....)和munmap;你可能有自己的分配器和释放器(至少对于大型对象,或者在你的类中一些operator newoperator delete等),阅读C++ @ 987654334@。但是您的标准newdelete(以及用于C 代码的mallocfree,C++ 经常使用newdelete)正在使用它们。

请注意,大多数freedelete 不会调用munmap,而只是将释放的内存标记为可供将来mallocnew 重用...

您绝对应该更加熟悉garbage collection 技术和术语。阅读GC handbook

另请参阅mallinfo(3) & mallopt(3) & proc(5)(可能在程序内部使用/proc/self/maps/proc/self/smaps & /proc/self/statm 来了解您的堆,或pmap 命令)。也许strace(1) 可能有用(了解syscalls(2) 发生了什么)

【讨论】:

  • 我对你的热心帮助表示同情,但是我担心如果 OP 最终澄清了这个问题,那么匆忙回答问题可能会浪费你的努力:毕竟这可能是由于操作系统/malloc。
  • 感谢有关 mallinfo 和 mallopt 的信息:“使用 mmap(2) 分配内存具有显着优势,即分配的内存块始终可以独立释放回系统。(相比之下,堆只有在顶端释放内存时才能修剪。)“。默认情况下,阈值看起来也是动态的,因此它会了解我的 4MB 分配块并提高阈值。
  • 我将 M_MMAP_THRESHOLD 设置为小于我的块大小,并希望基于几分钟的运行感到乐观。我会在早上知道这是否能解决我的问题。你能想到设置它的任何注意事项吗?
  • 由于 M_MMAP_THRESHOLD 设置为小于我的块大小,我现在看到我的内存使用量在我预期的数据存储大小上保持不变。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-08-24
  • 2013-05-24
  • 2021-11-20
  • 2011-06-01
  • 2019-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多