使用malloc分配页面时出现内存泄漏

Lui*_*BOL 8 c linux malloc memory-leaks memory-management

考虑以下C代码,它创建100,000个4KB大小的页面,然后释放99,999页,最后释放最后一页:

#include <stdio.h>
#include <stdlib.h>

#define NUM_PAGES 100000

int main() {
    void *pages[NUM_PAGES];

    int i;
    for(i=0; i<NUM_PAGES; i++) {
        pages[i] = malloc(4096);
    }

    printf("%d pages allocated.\n", NUM_PAGES);
    getchar();

    for(i=0; i<NUM_PAGES-1; i++) {
        free(pages[i]);
    }

    printf("%d pages freed.\n", NUM_PAGES-1);
    getchar();

    free(pages[NUM_PAGES-1]);

    printf("Last page freed.\n");
    getchar();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果你编译它,运行它并监视进程的内存使用情况,你可以看到内存使用量在第一个之前达到大约400MB getchar(当内存分配为100,000页时),即使在99,999页之后仍然保持相同分配(在第二个之后getchar),最后,当最后一页被解除分配时,它下降到1MB.

所以,我的问题是为什么会发生这种情况?为什么只有在释放所有页面时,整个内存才会返回到操作系统?是否有任何页面大小或任何页面对齐,以防止这种情况发生?我的意思是,当只有一个页面被释放时,是否有任何页面大小或对齐使得任何malloced页面完全返回到操作系统?

tem*_*def 5

这完全取决于实现,但我认为这与内存分配器的工作方式有关.通常,当内存管理器需要来自OS的更多内存时,它会调用该sbrk函数来请求额外的内存.该函数的典型实现是OS存储指向存储器中下一个空闲地址的指针,其中进程可以获得空间.内存像堆栈一样增长,与调用堆栈的工作方式大致相同.例如,如果您分配了五页内存,则可能如下所示:

 (existing memory) | Page 0 | Page 1 | Page 2 | Page 3 | Page 4 | (next free spot)
Run Code Online (Sandbox Code Playgroud)

使用此设置,如果您释放0到4页,程序内的内存管理器会将它们标记为空闲,如下所示:

 (existing memory) |                                   | Page 4 | (next free spot)
Run Code Online (Sandbox Code Playgroud)

由于操作系统以类似堆栈的方式分配内存,因此在完成使用之前,它无法从程序中回收所有这些内存.一旦释放最后一页,进程的内存将如下所示:

 (existing memory) |                                              (next free spot)
Run Code Online (Sandbox Code Playgroud)

此时程序的内存管理器可以将大量的可用空间返回给操作系统:

 (existing memory) | (next free spot)
Run Code Online (Sandbox Code Playgroud)

换句话说,因为内存被分配为堆栈,所以在您释放最后分配的内容之前,操作系统无法回收任何内存.

希望这可以帮助!

  • 在Linux上,较大的分配使用`mmap()`,而不是`sbrk()`.当`free()`d时,内存映射的分配立即返回给操作系统.在我的Ubuntu 12.04.2 LTS x86-64上使用6GB内存,使用嵌入式GNU C库2.15-0ubuntu14,分配131072字节或更多`mmap()`ed.因此,建议使用`sbrk()`是完全的bollocks.更好的方法是将分配合并为更大的单位.这种方法应该适用于所有操作系统,BTW. (4认同)
  • 我建议使用`mmap`而不是`sbrk` (3认同)
  • @ LuisAntonioBotelhoO.Leite您可能需要依赖操作系统的调用才能直接从操作系统获取/释放内存.在Windows下,您使用[VirtualAlloc](http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v = vs.85).aspx)和[VirtualFree](http:// msdn. microsoft.com/en-us/library/windows/desktop/aa366892(v=vs.85).aspx).在unices上,使用[sbrk(2)](http://linux.die.net/man/2/sbrk).请注意,您被警告只使用malloc/free并避免使用sbrk. (2认同)