想象一下,您有一个“大”(32 字节)的可用内存:
----------------------------------
| |
----------------------------------
现在,分配其中的一些(5 次分配):
----------------------------------
|aaaabbccccccddeeee |
----------------------------------
现在,释放前四个分配,但不释放第五个:
----------------------------------
| eeee |
----------------------------------
现在,尝试分配 16 个字节。哎呀,我不能,尽管有几乎两倍的免费空间。
在具有虚拟内存的系统上,碎片问题比您想象的要小,因为大型分配只需要在内存中连续即可。virtual地址空间,不在physical地址空间。因此,在我的示例中,如果我的虚拟内存页面大小为 2 字节,那么我可以毫无问题地分配 16 字节。物理内存看起来像这样:
----------------------------------
|ffffffffffffffeeeeff |
----------------------------------
而虚拟内存(更大)可能如下所示:
------------------------------------------------------...
| eeeeffffffffffffffff
------------------------------------------------------...
内存碎片的典型症状是,您尝试分配一个大块,但无法分配,即使您似乎有足够的可用内存。另一个可能的结果是进程无法将内存释放回操作系统(因为它从操作系统分配的每个大块,对于malloc
等等来细分,其中还剩下一些东西,即使每个块的大部分现在都未使用)。
C++ 中防止内存碎片的策略是根据对象的大小和/或预期寿命从不同区域分配对象。因此,如果您要创建大量对象并稍后将它们全部销毁,请从内存池中分配它们。您在它们之间进行的任何其他分配都不会来自池,因此不会位于内存中的它们之间,因此内存不会因此而产生碎片。或者,如果您要分配大量相同大小的对象,则从同一个池中分配它们。那么池中的一段可用空间永远不会小于您尝试从该池分配的大小。
一般来说,您不需要太担心,除非您的程序长时间运行并且进行大量分配和释放。当你同时拥有短寿命和长寿命的对象时,你面临的风险最大,但即便如此malloc
将尽力提供帮助。基本上,忽略它,直到您的程序分配失败或意外导致系统内存不足(在测试中捕获此问题,以供优先选择!)。
标准库并不比任何分配内存的东西差,标准容器都有一个Alloc
如果绝对必要,您可以使用模板参数来微调其分配策略。