小编典典

什么是内存碎片?

all

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

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

还:

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

阅读 66

收藏
2022-05-26

共1个答案

小编典典

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2022-05-26