C++:这看起来像内存碎片化吗?

4

总结:

我的应用程序消耗的内存比预期多得多(大约是预期量的250%),但我似乎找不到任何内存泄漏。调用相同的函数(它执行许多分配)将使内存使用量增加到某个点,然后它将不会改变并保持在那里。

程序细节:

该应用程序使用四叉树数据结构来存储“点”。可以指定要存储在内存中的最大点数(缓存大小)。'Points' 存储在 'PointBuckets' 中(链接到四叉树的叶节点的点数组),如果达到四叉树中的最大总点数,则将其序列化并保存到临时文件中,以便在需要时检索。这一切似乎都很好地工作。

现在,当加载文件时,会创建一个新的四叉树,并删除旧的四叉树(如果存在),然后逐个从文件中读取点并插入到四叉树中。在节点拆分等过程中创建和删除桶时进行了大量的内存分配。

症状:

如果我只加载一次预计使用300MB内存的文件,则会消耗预期的内存量。一切正常。如果我一遍又一遍地加载同一个文件,则内存使用量会不断增长(我在Linux的“top”命令中查看RES列),直到大约700MB。这可能表明存在内存泄漏。但是,如果我继续加载文件,内存消耗量仍然保持在700MB。

另一件事:当我使用valgrind massif并查看内存使用情况时,它始终保持在预期限制范围内。例如,如果我将缓存大小指定为1.5 GB并单独运行我的程序,则最终将消耗4GB的内存。如果我在massif中运行它,则它将始终保持在2GB以下,然后在生成的图表中,我将能够看到它实际上从未分配超过预期的1.5GB。我天真的假设是这种情况发生是因为massif使用自定义内存池,以某种方式防止了碎片。

那么你认为这里发生了什么?如果是内存碎片,应该寻找什么样的解决方案来解决这个问题?


1
听起来像是内存泄漏...只使用valgrind是否报告了任何丢失的内存? - Collin
1
他已经说了Valgrind没有显示任何泄漏。 - nhed
@nhed(他/她)说massif没有显示内存增益,但仅使用valgrind会报告泄漏。 - Collin
如果这是一个内存泄漏的问题,那么它不就应该是持续性的吗?内存使用量会无限增长而不是在某个点上稳定下来。 - jaho
1个回答

3
我会更简单地称它为基本的分配器和操作系统缓存行为。它们保留您分配的内存而不释放它,以便在下一次请求时更快地返回给您。然而,250%听起来很多,这可能会导致碎片化问题。
尝试将您的分配器替换为无碎片的分配器,例如对象池或内存池。

太好了,jemalloc已经解决了这个问题。我很惊讶它的工作效果如此出色! - jaho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接