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页面完全返回到操作系统?
这完全取决于实现,但我认为这与内存分配器的工作方式有关.通常,当内存管理器需要来自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)
换句话说,因为内存被分配为堆栈,所以在您释放最后分配的内容之前,操作系统无法回收任何内存.
希望这可以帮助!