【问题标题】:Fail to malloc big block memory after many malloc/free small blocks memory在许多 malloc/free 小块内存后无法 malloc 大块内存
【发布时间】:2014-07-17 10:38:14
【问题描述】:

这里是代码。

首先我尝试 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 %s\n", (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 %d\n", 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 %s\n", (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 时会发生内存碎片。

但是我已经释放了一切我 malloc,内存应该是空的。

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

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

【问题讨论】:

  • 可能内存还是碎片化的。您是否尝试过在程序运行时监控内存发生了什么?
  • @DieterLücking 我也这么认为,但是free()-loop 在遇到第一个NULL 时结束。
  • @DieterLücking 当 smalloc malloc 失败时, malloc 返回 NULL。在第二个 for 循环中,我检查 small_malloc[i] != NULL 以保护未初始化的指针。
  • 显然,VC++ 无法重新组合相邻的空闲内存块。在 32 位 Linux 上使用 GCC,它可以工作。
  • 问题不是VC++而是libc的堆管理器。默认情况下,windows 的堆管理器非常保守,但是有一个 API 可以请求使用新的堆管理器

标签: c++ c windows heap-memory fragmentation


【解决方案1】:

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

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

无法保证如果释放所有内存,竞技场将缩小到原始大小。可能竞技场还在那里,并且所有块都已放入空闲列表(可能合并成更大的块)。

在您的地址空间中存在这个挥之不去的竞技场可能无法满足大型分配请求。

【讨论】:

    【解决方案2】:

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

    您最初的大分配最终被一个分配块跟踪;但是,当您开始分配大量 3k 内存块时,您的堆会被分割成块。

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

    分配器似乎使用了 16M 块,一旦这些块被释放,它们就永远不会返回到空闲池中(即这些块保持分配状态)。

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

    【讨论】:

      【解决方案3】:

      即使我对此知之甚少,我还是找到了以下主题Why does malloc not work sometimes?,它涵盖了与您的主题相似的主题。 它包含以下链接: http://www.eskimo.com/~scs/cclass/int/sx7.html(指针分配策略) http://www.gidforums.com/t-9340.html(malloc 失败的原因?)

      【讨论】:

      • 只是一个评论:我在 CVI 2013 内置的 Win 7 32 位/4GB 下尝试了你的代码,没有你描述的问题,所以它可能是 VC2010(或其子部分)特定的。
      猜你喜欢
      • 2011-02-02
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 2011-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多