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

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

另外:

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


当前回答

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

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

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

其他回答

内存碎片与磁盘碎片是同一个概念:它指的是由于正在使用的区域没有足够紧密地打包在一起而浪费的空间。

举个简单的例子,假设你有10个字节的内存:

 |   |   |   |   |   |   |   |   |   |   |
   0   1   2   3   4   5   6   7   8   9

现在让我们分配三个3字节的块,命名为A, B和C:

 | A | A | A | B | B | B | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

现在释放block B:

 | A | A | A |   |   |   | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

如果我们分配一个4字节的块D会发生什么?好吧,我们有四个字节的空闲内存,但是我们没有四个连续的空闲内存,所以我们不能分配D!这是对内存的低效使用,因为我们应该能够存储D,但我们做不到。我们不能移动C语言来腾出空间,因为程序中的一些变量很可能指向C语言,我们不能自动找到并更改所有这些值。

你怎么知道这是个问题?那么,最大的迹象就是程序的虚拟内存大小比实际使用的内存量大得多。在现实世界的示例中,您将拥有超过10个字节的内存,因此D将从字节9开始分配,而字节3-5将一直未使用,除非稍后分配长度为3字节或更小的内存。

在这个例子中,3个字节并不是很大的浪费,但是考虑一个更病态的情况,两个字节的分配,例如,内存中间隔10兆字节,而您需要分配一个大小为10兆字节+ 1字节的块。你必须要求操作系统提供超过10兆字节的虚拟内存,即使你只差一个字节就有足够的空间了。

How do you prevent it? The worst cases tend to arise when you frequently create and destroy small objects, since that tends to produce a "swiss cheese" effect with many small objects separated by many small holes, making it impossible to allocate larger objects in those holes. When you know you're going to be doing this, an effective strategy is to pre-allocate a large block of memory as a pool for your small objects, and then manually manage the creation of the small objects within that block, rather than letting the default allocator handle it.

In general, the fewer allocations you do, the less likely memory is to get fragmented. However, STL deals with this rather effectively. If you have a string which is using the entirety of its current allocation and you append one character to it, it doesn't simply re-allocate to its current length plus one, it doubles its length. This is a variation on the "pool for frequent small allocations" strategy. The string is grabbing a large chunk of memory so that it can deal efficiently with repeated small increases in size without doing repeated small reallocations. All STL containers in fact do this sort of thing, so generally you won't need to worry too much about fragmentation caused by automatically-reallocating STL containers.

当然,STL容器不会在彼此之间共享内存,所以如果你要创建许多小容器(而不是几个经常调整大小的容器),你可能需要像处理任何经常创建的小对象(不管是不是STL)一样,注意防止碎片化。

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

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

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

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

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

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

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

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

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

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

这就是所谓的碎片化。

什么是内存碎片?

Memory fragmentation is the problem of memory becoming unusable even though it is theoretically available. There are two kinds of fragmentation: internal fragmentation is memory that is allocated but cannot be used (e.g. when memory is allocated in 8 byte chunks but the program repeatedly does single allocations when it needs only 4 bytes). external fragmentation is the problem of free memory becoming divided into many small chunks so that large allocation requests cannot be met although there is enough overall free memory.

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

如果您的程序使用的系统内存远远超过其实际有效负载数据所需的内存(并且您已经排除了内存泄漏),那么内存碎片就是一个问题。

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

使用一个好的内存分配器。在IIRC中,那些使用“最佳匹配”策略的人通常在避免碎片化方面要出色得多,只是速度稍慢一些。然而,事实也表明,对于任何配置策略,都存在病态的最坏情况。幸运的是,对于分配器来说,大多数应用程序的典型分配模式实际上是相对友好的。如果你对细节感兴趣,这里有一堆文件:

Paul R. Wilson, Mark S. Johnstone, Michael Neely and David Boles. Dynamic Storage Allocation: A Survey and Critical Review. In Proceedings of the 1995 International Workshop on Memory Management, Springer Verlag LNCS, 1995 Mark S.Johnstone, Paul R. Wilson. The Memory Fragmentation Problem: Solved? In ACM SIG-PLAN Notices, volume 34 No. 3, pages 26-36, 1999 M.R. Garey, R.L. Graham and J.D. Ullman. Worst-Case analysis of memory allocation algorithms. In Fourth Annual ACM Symposium on the Theory of Computing, 1972