Memory allocation for global and local variables
我已经知道全局变量的内存是在程序启动时分配的,而局部变量的内存是在函数调用时分配的。
案例1:我声明了一个大小为63500000的全局整数数组,使用的内存为256 MB理想链路
1 2 3 4 5 6 7 8 | include <stdio.h> int a[63500000]; int main() { printf ("This code requires about 250 MB memory "); return 0; } |
案例2:我在main()中声明了一个相同大小的本地整数数组,使用的内存为1.6 MB理想链路
1 2 3 4 5 6 7 8 9 10 | #include <stdio.h> int main() { int a[63500000]= {1,5,0}; printf ("This code requires only 1.6 MB "); //printf ("%d ", a[0]); return 0; } |
案例3:我在另一个函数中声明了一个相同大小的局部整数数组,使用的内存为1.6 MB理想链路
1 2 3 4 5 6 7 8 9 10 11 | #include <stdio.h> void f() { int a[63500000]; } int main() { f(); return 0; } |
请解释一下为什么使用的内存不同或我的内存分配概念错误??
首先:IDeone编译器是gcc。
那么,当您编译这个代码时,GCC会做什么呢?:
1 2 3 4 | void foo () { int a[63500000]; } |
1 2 3 4 5 | foo: pushl %ebp movl %esp, %ebp popl %ebp ret |
也就是说,堆栈上根本没有分配任何内容。
这个数组只是被gcc优化掉了,因为它从未被使用过。
gcc不会对一个全局进行这样的处理,因为有可能在另一个编译单元中使用了一个全局,因此它不确定它是否从未被使用过。另外:全局不在堆栈上(因为它是全局的)。
现在,让我们看看实际使用本地数组时会发生什么:
1 2 3 4 5 6 7 | int bar (int a, int b, int c) { int f[63500000]; f[a] = 9; f[b] = 7; return f[c]; } |
情况非常不同:
1 2 3 4 5 6 7 8 9 10 11 12 | bar: pushl %ebp movl %esp, %ebp subl $254000000, %esp movl 8(%ebp), %eax movl $9, -254000000(%ebp,%eax,4) movl 12(%ebp), %eax movl $7, -254000000(%ebp,%eax,4) movl 16(%ebp), %eax movl -254000000(%ebp,%eax,4), %eax leave ret |
此行:
现在,如果我试图在程序中使用
1 2 3 4 5 6 7 8 9 10 11 12 | int bar (int a, int b, int c) { int f[63500000]; f[a] = 9; f[b] = 7; return f[c]; } int main (void) { return bar (0, 0, 0); } |
我们已经看到,
1 | ulimit -s 1000000 #i.e. allow stack size to grow close to 1GB |
然后我可以运行这个程序,它确实会运行。
Ideone网站上失败的原因是,它们在执行程序时限制了堆栈大小(它们应该这样做,否则恶意用户可能会破坏系统)。
案例2, 3
在函数内部定义的变量在堆栈上分配。这意味着当函数退出时,相关的内存被清除(栈被"弹出")。
案例1
全局范围中定义的变量被分配到进程生命周期中存在的数据段(或者通常是从操作系统请求的内存空间)中。
另外
使用malloc分配的内存是从堆中分配的,并且在使用free显式释放之前保持分配状态。
请注意,现代操作系统可以很好地提供程序请求的地址空间,但在物理访问内存(或通常称为页面的内存的一部分)之前,不能用RAM返回该地址空间。
当您请求64MB的堆栈内存时,
这个答案很好地解释了进程地址空间(.text,.bss,.data)的各个部分以及如何完成变量的各种分配。