什么是内存碎片?

新手上路,请多包涵

我听说过在 C++ 动态内存分配的上下文中多次使用“内存碎片”这个术语。我发现了一些关于如何处理内存碎片的问题,但找不到处理它本身的直接问题。所以:

  • 什么是内存碎片?
  • 如何判断内存碎片是否是我的应用程序的问题?什么样的程序最容易受到影响?
  • 处理内存碎片的常用方法有哪些?

还:

  • 我听说大量使用动态分配会增加内存碎片。这是真的?在 C++ 的上下文中,我了解所有标准容器(std::string、std::vector 等)都使用动态内存分配。如果在整个程序中使用这些(尤其是 std::string),内存碎片是否更有可能成为问题?
  • 如何在 STL 繁重的应用程序中处理内存碎片?

原文由 AshleysBrain 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

想象一下,你有一个“大”(32 字节)的可用内存:

 ----------------------------------
|                                |
----------------------------------

现在,分配其中的一些(5 个分配):

 ----------------------------------
|aaaabbccccccddeeee              |
----------------------------------

现在,释放前四个分配,但不释放第五个:

 ----------------------------------
|              eeee              |
----------------------------------

现在,尝试分配 16 个字节。哎呀,我不能,即使有几乎两倍的免费。

在具有虚拟内存的系统上,碎片问题比您想象的要小,因为大分配只需要在 虚拟 地址空间中是连续的,而不是在 物理 地址空间中。所以在我的例子中,如果我有一个页面大小为 2 个字节的虚拟内存,那么我可以毫无问题地分配我的 16 个字节。物理内存如下所示:

 ----------------------------------
|ffffffffffffffeeeeff            |
----------------------------------

而虚拟内存(更大)可能如下所示:

 ------------------------------------------------------...
|              eeeeffffffffffffffff
------------------------------------------------------...

内存碎片的典型症状是您尝试分配一个大块并且您不能,即使您似乎有足够的可用内存。另一个可能的后果是进程无法将内存释放回操作系统(因为它从操作系统分配的每个大块,用于 malloc 等进行细分,都有一些东西留在里面,即使每个块的大部分现在都未使用)。

C++ 中防止内存碎片的策略是根据对象的大小和/或预期的生命周期从不同的区域分配对象。因此,如果您要创建大量对象并稍后将它们全部销毁,请从内存池中分配它们。您在它们之间进行的任何其他分配都不会来自池,因此不会位于它们之间的内存中,因此内存不会因此而碎片化。或者,如果您要分配大量相同大小的对象,则从同一个池中分配它们。然后,池中的一段可用空间永远不会小于您尝试从该池分配的大小。

通常你不需要太担心它,除非你的程序是长时间运行的并且做了很多分配和释放。当您同时拥有短寿命和长寿命对象时,您的风险最大,但即便如此, malloc 也会尽最大努力提供帮助。基本上,忽略它,直到您的程序分配失败或意外导致系统内存不足(在测试中抓住这一点,优先考虑!)。

标准库并不比其他分配内存的库差,标准容器都有一个 Alloc 模板参数,如果绝对必要,您可以使用它来微调它们的分配策略。

原文由 Steve Jessop 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题