有些分配器是懒惰的吗?

Lir*_*evi 10 linux malloc memory-management

我在Linux中编写了一个C语言程序,用于mallocs内存,在循环中运行它,而TOP没有显示任何内存消耗.

然后我用那个记忆做了一些事情,TOP确实显示了内存消耗.

当我在malloc时,我真的"得到了内存",还是有一个"懒惰"的内存管理,只有在我使用它时才给我内存?

(还有一个选项,当我使用它时TOP才知道内存消耗,所以我不确定这个...)

谢谢

bdo*_*lan 18

在Linux上,malloc使用sbrk()或mmap()请求内存 - 无论哪种方式,您的地址空间都会立即扩展,但Linux在第一次写入相关页面之前不会分配实际的物理内存页面.您可以在VIRT列中看到地址空间扩展,而在RES中可以看到实际的物理内存使用情况.


Rob*_*nes 6

这从主题开始(然后我将其与您的问题联系在一起),但是发生的事情类似于在Linux中派生一个进程时发生的事情。派生时,有一种称为写时复制的机制,该机制也仅在写入内存时才为新进程复制内存空间。这样,如果分叉的流程执行程序立即是一个新程序,那么您就节省了复制原始程序内存的开销。

回到您的问题,这个想法是相似的。正如其他人指出的那样,请求内存会立即为您提供虚拟内存空间,但是实际页面仅在写入它们时才分配。

目的是什么?它基本上使对内存的分配成为一个或多或少的固定时间操作Big O(1)而不是Big O(n)操作(类似于linux调度程序的工作方式,而不是大块地进行)。

为了证明我的意思,我做了以下实验:

rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc 

real    0m0.005s
user    0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef 

real    0m0.558s
user    0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites 

real    0m0.006s
user    0m0.000s
sys 0m0.008s
Run Code Online (Sandbox Code Playgroud)

bigmalloc程序分配2000万个整数,但不对其进行任何处理。deadbeef向每个页面写入一个int,导致19531次写入,justwrites分配19531个int,然后将它们清零。如您所见,deadbeef的执行时间比bigmalloc长100倍,比justwrites长约50倍。

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

return 0;

}
Run Code Online (Sandbox Code Playgroud)

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

// immediately write to each page to simulate all at once allocation

// assuming 4k page size on 32bit machine

for ( int* end = big + 20000000; big < end; big+=1024 ) *big = 0xDEADBEEF ;    

return 0;

}
Run Code Online (Sandbox Code Playgroud)

#include <stdlib.h>

int main(int argc, char **argv) {

int *big = calloc(sizeof(int),19531); // number of writes

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