在许多malloc/释放小块内存后,未能malloc大块内存

Fail to malloc big block memory after many malloc/free small blocks memory

本文关键字:内存 malloc 未能 许多 释放      更新时间:2023-10-16

代码如下:

首先我尝试malloc并释放一个大块内存,然后我malloc许多小块内存,直到内存用完,我释放所有这些小块。

之后,我尝试malloc一个大块内存。

#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
    static const int K = 1024;
    static const int M = 1024 * K;
    static const int G = 1024 * M;
    static const int BIG_MALLOC_SIZE = 1 * G;
    static const int SMALL_MALLOC_SIZE = 3 * K;
    static const int SMALL_MALLOC_TIMES = 1 * M;
    void **small_malloc = (void **)malloc(SMALL_MALLOC_TIMES * sizeof(void *));
    void *big_malloc = malloc(BIG_MALLOC_SIZE);
    printf("big malloc first time %sn", (big_malloc == NULL)? "failed" : "succeeded");
    free(big_malloc);
    for (int i = 0; i != SMALL_MALLOC_TIMES; ++i)
    {
        small_malloc[i] = malloc(SMALL_MALLOC_SIZE);
        if (small_malloc[i] == NULL)
        {
            printf("small malloc failed at %dn", i);
            break;
        }
    }
    for (int i = 0; i != SMALL_MALLOC_TIMES && small_malloc[i] != NULL; ++i)
    {
        free(small_malloc[i]);
    }
    big_malloc = malloc(BIG_MALLOC_SIZE);
    printf("big malloc second time %sn", (big_malloc == NULL)? "failed" : "succeeded");
    free(big_malloc);
    return 0;
}

结果如下:

big malloc first time succeeded
small malloc failed at 684912
big malloc second time failed

好像有内存碎片。

我知道当内存中有很多小的空白空间,但是没有足够大的空白空间来容纳大的malloc时,就会发生内存碎片。

但是我已经释放了所有 I malloc,内存应该是空的。

为什么我不能在第二次malloc大块?

我在Windows 7上使用Visual Studio 2010,我构建32位程序。

遗憾的是,答案仍然是碎片化。

初始的大分配最终被一个分配块跟踪;然而,当你开始分配大量的3k内存块时,堆就会被切成块。

即使在释放内存时,块的一小部分仍然在进程的地址空间中分配。您可以使用Sysinternals VMMap之类的工具直观地查看这些分配。

看起来分配器使用了16M块,一旦这些块被释放,它们就不会返回到空闲池(即块仍然被分配)。

因此,您没有足够的连续内存来第二次分配1GB块。

即使我知道这一点,我发现下面的线程为什么malloc有时不工作?内容和你的相似。它包含以下链接:http://www.eskimo.com/~scs/cclass/int/sx7.html(指针分配策略)http://www.gidforums.com/t-9340.html (malloc失败的原因?)

问题很可能是,即使您释放了每个分配,malloc也不会将所有内存返回给操作系统。

当您的程序请求大量较小的分配时,malloc必须增加它分配内存的"竞技场"的大小。

不能保证释放所有内存后竞技场会缩小到原来的大小。有可能竞技场仍然在那里,所有的块都被放入了一个空闲列表中(也许合并成更大的块)。

如果地址空间中存在这个区域,可能无法满足大的分配请求。