内存碎片与磁盘碎片是同一个概念:它指的是由于正在使用的区域没有足够紧密地打包在一起而浪费的空间。
举个简单的例子,假设你有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)一样,注意防止碎片化。