malloc()和free()后似乎仍有一些内存被分配。

4

我刚开始学习C语言。我试着熟悉malloc和free的用法。我写了下面这个测试代码,但是不知道为什么内存没有被完全释放(top命令仍然显示该进程分配了约150MB的内存)。这是为什么呢?

#include <stdio.h>
#include <malloc.h>

typedef struct {
    char *inner;
} structure;

int main()
{
    int i;
    structure** structureArray;

    structureArray = (structure**)malloc(sizeof(structure*)*1000*10000);
    for (i = 0; i < 1000*10000;i++)
    {
        structureArray[i] = (structure*) malloc(sizeof(structure));
        structureArray[i]->inner = (char*) malloc(sizeof(char)*1000*1000*1000);
    }

    printf("freeing memory");
    for (i = 0; i < 1000*10000;i++)
    {
        free(structureArray[i]->inner);
        free(structureArray[i]);
    }
    free(structureArray);

    system("sleep 100");
    return 0;
}

对应的 Makefile:

all: test.c
    gcc -o test test.c
    ./test &
    top -p `pidof ./test`
    killall ./test

2
你试过打开mudflap或者valgrind测试吗?它们会给你更好的内存泄漏统计数据。 - Robert Massaioli
2
你意识到你正在尝试分配多少内存吗? - rlbond
谁在乎呢?这是一个64位系统——地址空间并不是一种稀缺资源。系统从来没有给你独占物理内存(RAM)的控制权。 - David Schwartz
3个回答

12

top会告诉您分配给进程的物理内存量。虚拟内存是在物理内存之上的抽象,而malloc/free则在其之上提供了一种抽象。

malloc从程序的堆中保留空间。堆只是程序虚拟地址空间中用于临时存储的区域。随着调用malloc的次数增多,堆会使用brk系统调用扩展。然而,尽管堆的虚拟大小增加了,但直到您读取或写入新分配的内存之前,物理内存实际上并没有分配。例如,由于您从未写入记录的inner字段分配的内存,因此这些分配将不占用任何物理RAM。

free仅释放malloc分配的堆的部分。这并不一定会减少堆的虚拟大小,因此与其关联的物理内存可能不会被释放。这就是为什么您没有看到物理内存使用量减少的原因。


谢谢,这个解释非常详尽。 - Filip Nguyen

7
Unix内存管理是一种懒惰的方式,除非没有人真正需要它,否则不能保证释放进程内存。这里有一篇好文章:点击查看

另外,我建议您检查malloc()的结果,您肯定会发现至少有一些失败了。

malloc失败的原因是操作系统不再允许进程分配更多的内存空间。 - Evan

3

可能是因为您分配了约10000000000000000字节(1000 * 10000 * 1000 * 1000 * 1000)=〜10000000000兆字节= 10000000千兆字节,这将多次超出您的系统内存。


如果OP使用的是64位系统,那么就不会执行此操作。 - Jay Conrod
在64位Linux上,尽管分配了如此多的内存,但由于使用了惰性分配器,因此您可以轻松应对。 在几乎任何其他地方,您早就用完了(虚拟)内存。 而在Linux上,您将用完内存。 我想为您点赞,但您需要指出它并不像“多次包装系统内存”那样简单。 - Jonathan Leffler
系统内存指的是物理内存,而不是虚拟内存。看起来提问者的系统不太可能有10000000 G字节的物理内存,因此该程序可能并非预期的目的。 - dajobe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接