这一直困扰着我很长一段时间:让我说我有一个功能:
void test(){
int t1, t2, t3;
int t4 = 0;
int bigvar[10000];
// do something
}
计算机如何处理变量的内存分配?
我一直认为变量空间保存在计算机将读取的.exe中,这是正确的吗?但据我所知,bigvar
数组在.exe中不占用10000 int
个元素空间,因为它未初始化。那么当我调用函数时,它的内存分配如何工作?
答案 0 :(得分:9)
这些局部变量通常使用处理器的stack来实现。这意味着编译器唯一需要做的就是计算每个变量的大小,并将它们加在一起。总和是在函数入口处更改堆栈指针的数量,并在退出时更改回来。然后访问每个变量,使其相对偏移到堆栈中的该内存块。
您的代码在Linux中编译时,在x86汇编程序中看起来像这样:
test:
pushl %ebp
movl %esp, %ebp
subl $40016, %esp
movl $0, -4(%ebp)
leave
ret
在上面,常量$ 40016是四个32位整数t1, t2, t3
和t4
所需的空间,而剩余的40000个字节代表10000个元素的数组bigvar
答案 1 :(得分:0)
除了一些笔记之外,我不能对已经说过的内容添加太多内容。实际上,您可以将局部变量放入可执行文件中,并将它们分配到数据段(并初始化)而不是堆栈段。为此,请将它们声明为static
。但是,然后函数的所有调用将共享相同的变量,而在堆栈中,每次调用都会创建一组新的变量。当多个线程同时调用函数或者有递归时(试图想象),这会导致很多麻烦。这就是为什么大多数语言都使用堆栈作为局部变量而很少使用static
。
答案 2 :(得分:0)
在一些旧的编译器上,我遇到了静态分配数组的行为。这意味着它在加载程序时为它留出内存,并在此之后使用该空间。这种行为是不安全的(参见谢尔盖的答案),我也不希望根据标准允许它,但我在野外遇到过它。 (我对它的编译器没有记忆。)
在大多数情况下,局部变量保留在堆栈中,以及返回地址和所有其他内容。这意味着未初始化的值可能包含敏感信息。根据unwind的回答,这也包括数组。
另一个有效的实现是在堆栈上找到的变量是一个指针,并且编译器在引擎盖下进行分配和释放(可能是以异常安全的方式)。这将节省堆栈空间(必须在程序启动之前分配,并且不能轻易地扩展到x86架构),并且对于C标准VLA(可变长度数组,又名穷人的std :: vector)非常有用