我了解到全局变量的内存是在程序启动时分配的,而局部变量的内存是在进行函数调用时分配的。
案例一:
我声明了一个大小为 63500000 的全局整数数组,使用的内存为 256 MB
Ideone Link
include <stdio.h>
int a[63500000];
int main()
{
printf ("This code requires about 250 MB memory\n");
return 0;
}
案例二:
我在 main() 中声明了一个相同大小的本地整数数组,使用的内存为 1.6 MB
Ideone link
#include <stdio.h>
int main()
{
int a[63500000]= {1,5,0};
printf ("This code requires only 1.6 MB \n");
//printf ("%d\n", a[0]);
return 0;
}
案例三:
我在另一个函数中声明了一个相同大小的本地整数数组,使用的内存为 1.6 MB
Ideone Link
#include <stdio.h>
void f()
{
int a[63500000];
}
int main()
{
f();
return 0;
}
请解释为什么使用的内存不同或者我的内存分配概念是错误的??
最佳答案
首先:ideone的编译器是GCC。
那么,当你编译这个时,GCC 做了什么?:
void foo ()
{
int a[63500000];
}
gcc -S -O2 foo.c
生成:
foo:
pushl %ebp
movl %esp, %ebp
popl %ebp
ret
即没有分配到堆栈上,根本。
数组只是被 GCC 优化掉了,因为它从未被使用过。
GCC 不会对全局执行此操作,因为全局可能在另一个编译单元中使用,因此不确定它是否从未使用过。另外:全局变量不在堆栈上(因为它是全局变量)。
现在,让我们看看当您实际使用本地数组时会发生什么:
int bar (int a, int b, int c)
{
int f[63500000];
f[a] = 9;
f[b] = 7;
return f[c];
}
情况非常不同:
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
这一行:subl $254000000, %esp
对应数组的大小。即内存是在堆栈上分配的。
现在,如果我尝试在程序中使用 bar
函数会怎样:
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);
}
我们已经看到,bar
函数在堆栈上分配了 250 兆字节左右的空间。在我的默认 GNU/Linux 安装中,堆栈大小限制为 8MB。所以当程序运行时,会导致“Segmentation fault”。如果需要,我可以通过在 shell 中执行以下命令来增加它:
ulimit -s 1000000 #i.e. allow stack size to grow close to 1GB
然后我就可以运行程序了,果然可以运行。
在 ideone 网站上失败的原因是他们在执行程序时限制了堆栈大小(他们应该这样做,否则恶意用户可能会搞砸他们的系统)。
关于c - 全局和局部变量的内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11977316/