在下面的 C 程序中,对函数的调用创建了一个相当大的局部变量buf,然后函数返回并且程序处于无限循环中。buf正如人们所预料的那样,在调用该函数时,系统的 RAM 使用量会增加等于 的大小;但是,函数返回后(显示“完成”),RAM 使用量不会下降,而是保持不变。
为什么函数返回后这个堆栈分配的缓冲区没有立即释放?如何制定这种行为的一般行为,并描述在哪些情况下它可能会或可能不会立即释放?
#include <stdlib.h>
#include <stdio.h>
void f()
{
int buf[1000 * 1000 * 200];
}
int main()
{
f();
printf("Done\n");
for (;;);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
PS 这是在 Linux Ubuntu 上运行的。
PS 我编译时没有进行编译器优化
PSf以“闪烁”方式调用(重复[开 - 延迟 - 关 - 延迟])而不是一次调用会导致类似的 RAM 使用时间线。
\n\n为什么函数返回后这个堆栈分配的缓冲区没有立即释放?
\n
一般来说,在函数返回后,堆栈分配的内存永远不会被释放,至少不会以您期望的方式释放。
\n随着堆栈的增长,操作系统会自动为其分配更多内存。但它是一个单向进程\xe2\x80\x94,因为函数返回并且堆栈被弹出,内存不会从进程中释放。假设是,如果程序一次需要那么多堆栈帧(或那么大的堆栈帧),那么它很可能会再次需要它。当然,这是一个相当有效的假设:任何被调用并导致堆栈增长到一定深度的函数都可能会再次被调用。
\n另一方面,在每个函数返回时重复释放堆栈内存并在新调用函数时重新分配堆栈内存,在大多数情况下是完全低效的(更不用说不必要的)。
\n多说一点...
\n一般来说,有两种或三种不同级别的内存分配:
\n当您调用函数且堆栈增长时,它会利用已分配但未使用的堆栈空间(如果存在),或者如果内存不足,操作系统会自动分配更多内存(在意义上 1 中)。但是当函数返回时,它以前的堆栈空间只是变得未使用(在意义 2 中);它不会从进程中释放并返回到操作系统(意义上 1)。
\n类似地,当您调用malloc请求一些动态分配的内存时,malloc如果有足够的可用内存,实现会使用其“池”(或堆),或者它会向操作系统请求更多内存(在意义上 1)但是,当您调用free返回不再需要的动态分配的内存时,它会返回到malloc池中并变得未使用(在意义上2);它通常不会从进程中释放并返回到操作系统(在意义上1)。
虚拟内存的换入或换出(意义 3)是完全自动的,尽管通常它与内存是否正在使用(意义 2)密切相关。
\n