我在同一主题的类似帖子中给出了这个答案:
Are some allocators lazy?
这开始有点偏离主题(然后我会将它与您的问题联系起来),但是发生的事情类似于您在 Linux 中分叉一个进程时发生的事情。分叉时有一种称为写时复制的机制,它只在内存也被写入时为新进程复制内存空间。这样,如果分叉的进程 exec 立即成为一个新程序,那么您就节省了复制原始程序内存的开销。
回到你的问题,这个想法是相似的。正如其他人指出的那样,请求内存会立即为您提供虚拟内存空间,但实际页面仅在写入时分配。
这样做的目的是什么?它基本上使 mallocing 内存成为或多或少的恒定时间操作 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
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;
}
.
#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 an all-at-once allocation
// assuming 4k page size on a 32-bit machine.
for (int* end = big + 20000000; big < end; big += 1024)
*big = 0xDEADBEEF;
return 0;
}
.
#include <stdlib.h>
int main(int argc, char **argv) {
int *big = calloc(sizeof(int), 19531); // Number of writes
return 0;
}