我在Linux中编写了一个C语言程序,用于mallocs内存,在循环中运行它,而TOP没有显示任何内存消耗.
然后我用那个记忆做了一些事情,TOP确实显示了内存消耗.
当我在malloc时,我真的"得到了内存",还是有一个"懒惰"的内存管理,只有在我使用它时才给我内存?
(还有一个选项,当我使用它时TOP才知道内存消耗,所以我不确定这个...)
谢谢
在Linux上,malloc使用sbrk()或mmap()请求内存 - 无论哪种方式,您的地址空间都会立即扩展,但Linux在第一次写入相关页面之前不会分配实际的物理内存页面.您可以在VIRT列中看到地址空间扩展,而在RES中可以看到实际的物理内存使用情况.
这从主题开始(然后我将其与您的问题联系在一起),但是发生的事情类似于在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
bigmalloc程序分配2000万个整数,但不对其进行任何处理。deadbeef向每个页面写入一个int,导致19531次写入,justwrites分配19531个int,然后将它们清零。如您所见,deadbeef的执行时间比bigmalloc长100倍,比justwrites长约50倍。
#includeint main(int argc, char **argv) { int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes return 0; }
。
#includeint 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; }
。
#includeint main(int argc, char **argv) { int *big = calloc(sizeof(int),19531); // number of writes return 0; }