roo*_*oot 1 c operating-system memory-leaks
所以我有一个有趣的基于操作系统的问题.我花了最后几个小时与我认识的任何有C编程经验的人交谈,似乎没有人能够就这种行为发生的原因找到明确的答案.
我有一个故意设计用于导致极端内存泄漏的程序(作为分配后不释放内存时会发生什么的一个例子).在64位操作系统(Windows,Linux等)上,它可以做它应该做的事情.它填充物理内存,然后填充操作系统的交换空间.在Linux中,该过程随后由OS终止.然而,在Windows中,它不是,并且它继续运行.最终结果是系统崩溃.
这是代码:
#include <stdlib.h>
#include <stdio.h>
void main()
{
while(1)
{
int *a;
a = (int*)calloc(65536, 4);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您在32位Linux发行版上编译并运行此代码,则它根本不会影响物理内存使用.它占用了我4 GB分配RAM的大约1%,之后它永远不会上升.我没有32位Windows的合法副本进行测试,所以我不能确定这也发生在32位Windows上.
有人可以解释为什么使用calloc将填充64位Linux操作系统的物理内存,而不是32位Linux操作系统?
该malloc和calloc功能在技术上不分配内存,尽管他们的名字.它们实际上使用操作系统级别的读/写权限分配程序的部分地址空间.这是一个微妙的差异,大多数时候都不相关.
如编写的那样,该程序仅占用地址空间.最终,calloc将开始返回NULL但程序将继续运行.
#include <stdlib.h>
// Note main should be int.
int main() {
while (1) {
// Note calloc should not be cast.
int *a = calloc(65536, sizeof(int));
}
}
Run Code Online (Sandbox Code Playgroud)
如果你写入calloc返回的地址,它将强制内核分配内存来支持这些地址.
#include <stdlib.h>
#include <string.h>
int main() {
size_t size = 65536 * 4;
while (1) {
// Allocates address space.
void *p = calloc(size, 1);
// Forces the address space to have allocated memory behind it.
memset(p, 0, size);
}
}
Run Code Online (Sandbox Code Playgroud)
写入返回的块中的单个位置是不够的,calloc因为分配实际内存的粒度是4 KiB(页面大小... 4 KiB是最常见的).因此,只需写入每个页面即可.
分配地址空间有一些簿记开销.在64位系统上,您可以获得40或48位的地址空间,其中大约一半可以分配给程序,至少达到8 TiB.在32位系统上,这大约为2 GiB(取决于内核配置).
因此,在64位系统上,您可以分配~8 TiB,而32位系统可以分配~2 GiB,并且开销是导致问题的原因.每次调用malloc或通常都会有少量开销calloc.
另请参见为什么malloc + memset比calloc慢?