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

什么是内存碎片? 如何判断内存碎片是否是我的应用程序的一个问题?什么样的程序最可能受到影响? 处理内存碎片的常用方法是什么?

另外:

我听说经常使用动态分配会增加内存碎片。这是真的吗?在c++环境中,我知道所有的标准容器(std::string, std::vector等)都使用动态内存分配。如果在整个程序中使用这些(特别是std::string),内存碎片更可能是一个问题吗? 在stl较多的应用程序中如何处理内存碎片?


当前回答

什么是内存碎片?

内存碎片是指当您的大部分内存被分配为大量不连续的块或块时——留下很大比例的内存未分配,但在大多数典型场景下无法使用。这将导致内存溢出异常或分配错误(即malloc返回null)。

The easiest way to think about this is to imagine you have a big empty wall that you need to put pictures of varying sizes on. Each picture takes up a certain size and you obviously can't split it into smaller pieces to make it fit. You need an empty spot on the wall, the size of the picture, or else you can't put it up. Now, if you start hanging pictures on the wall and you're not careful about how you arrange them, you will soon end up with a wall that's partially covered with pictures and even though you may have empty spots most new pictures won't fit because they're larger than the available spots. You can still hang really small pictures, but most ones won't fit. So you'll have to re-arrange (compact) the ones already on the wall to make room for more..

现在,想象墙是你的(堆)内存,图片是物体。这就是内存碎片。

如何判断内存碎片是否是我的应用程序的一个问题?什么样的程序最可能受到影响?

您可能正在处理内存碎片的一个明显迹象是,如果您得到许多分配错误,特别是当已使用内存的百分比很高时(但不是您还没有使用完所有内存),那么从技术上讲,您应该有足够的空间用于您试图分配的对象。

当内存严重碎片化时,内存分配可能需要更长的时间,因为内存分配器必须做更多的工作来为新对象找到合适的空间。如果您有许多内存分配(您可能会这样做,因为您最终会产生内存碎片),分配时间甚至可能会导致明显的延迟。

处理内存碎片的常用方法是什么?

使用好的算法分配内存。不是为许多小对象分配内存,而是为这些小对象的连续数组预分配内存。有时,在分配内存时稍微浪费一点可以提高性能,并且可以省去必须处理内存碎片的麻烦。

其他回答

什么样的程序最可能受到影响?

关于与内存碎片相关的问题,一个很好的(=可怕的)例子是Stardock的电脑游戏“Elemental: War of Magic”的开发和发行。

这款游戏是基于32位/2GB内存构建的,所以必须在内存管理方面进行大量优化,以确保游戏能够在这2GB内存中运行。由于“优化”导致不断分配和取消分配,随着时间的推移,堆内存碎片发生,导致游戏每次都崩溃。

YouTube上有一个“战争故事”采访。

当分配和释放许多大小不同的对象时,最可能发生内存碎片。假设你在内存中有如下布局:

obj1 (10kb) | obj2(20kb) | obj3(5kb) | unused space (100kb)

现在,当obj2被释放时,您有120kb的未使用内存,但是您不能分配120kb的完整块,因为内存是碎片化的。

避免这种影响的常用技术包括环形缓冲区和对象池。在STL的上下文中,像std::vector::reserve()这样的方法可以提供帮助。

当你想在堆上添加一项时,会发生的事情是计算机必须搜索空间来容纳该项。这就是为什么动态分配不在内存池上执行或使用池分配程序会“减慢”速度的原因。对于一个沉重的STL应用程序,如果你正在做多线程,有囤积分配器或TBB英特尔版本。

现在,当内存碎片化时,会发生两件事:

There will have to be more searches to find a good space to stick "large" objects. That is, with many small objects scattered about finding a nice contigous chunk of memory could under certain conditions be difficult (these are extreme.) Memory is not some easily read entity. Processors are limited to how much they can hold and where. They do this by swapping pages if an item they need is one place but the current addresses are another. If you are constantly having to swap pages, processing can slow down (again, extreme scenarios where this impacts performance.) See this posting on virtual memory.

这是一个超级简化版的傻瓜。

当对象在内存中创建时,它们被添加到内存中已使用部分的末尾。

如果一个对象不在已使用内存部分的末尾被删除,这意味着这个对象位于其他两个对象之间,它将创建一个“洞”。

这就是所谓的碎片化。

关于内存碎片的详细答案可以在这里找到。

http://library.softwareverify.com/memory-fragmentation-your-worst-nightmare/

这是11年来我一直在softwareverify.com上回答人们关于内存碎片问题的答案的高潮