解除分配堆不被回收?

时间:2016-01-20 17:34:33

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

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

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

在总视图生成的堆报告中,我们看到了存储数据的10GB分配内存,但我们还看到了4 GB以上的#34; deallocated"记忆。通过堆显示,看起来我们的堆非常分散。会有很多"分配"记忆中穿插着大量的“解除分配”#34;存储器中。

  • "是否已取消分配"已被我的进程释放但未被操作系统回收的内存,是否合理地认为这可能是我们记忆的来源"泄漏"?

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

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

1 个答案:

答案 0 :(得分:3)

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

然后:

以上内容可帮助您捕捉剩余的memory leaks。准备好花几周时间。您可能需要停用ASLR,并且应该了解gdb观察点。

您也可以考虑使用Boehm's conservative garbage collector。有关在标准C ++ this中使用它的信息,请参阅containers。如果您使用的是Boehm的GC,那么您几乎可以在程序的每个地方使用它......

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

您可以(但我不一定建议)在OS virtual address space之上编写您自己的内存分配器,更改mmap(2)之类的原语(可能带有MAP_HUGETLB ....)& ; munmap;您可能拥有自己的分配器和解除分配器(至少对于大型对象,或者{em>} operator new等等,在您的类的部分中) ,阅读有关C ++ allocator concept的内容。但是,C ++ operator delete& new经常使用的标准deletemalloc(以及free& new C代码是使用它们。

请注意,大多数deletefree都不会调用delete,而只是将已释放的内存标记为将来munmapmalloc可重复使用...

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

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