全局变量和局部变量的内存分配

时间:2022-12-24 16:49:32

I have learnt that memory for global variables are allocated at program startup whereas memory for local variables are allocated whenever function call is made.

我已经知道全局变量的内存是在程序启动时分配的,而局部变量的内存是在进行函数调用时分配的。

Case 1:
I have declared a global integer array of size 63500000 and memory used is 256 MB
Ideone Link

情况1:我已经声明了一个大小为63500000的全局整数数组,并且使用的内存是256 MB Ideone Link

include <stdio.h>
int a[63500000];
int main()
{
    printf ("This code requires about 250 MB memory\n");
    return 0;
}

Case 2:
I have declared a local integer array of same size in main() and memory used is 1.6 MB
Ideone link

情况2:我在main()中声明了一个大小相同的本地整数数组,使用的内存是1.6 MB Ideone链接

#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;
}

Case 3:
I have declared a local integer array of same size in another function and memory used is 1.6 MB
Ideone Link

情况3:我在另一个函数中声明了一个大小相同的本地整数数组,使用的内存是1.6 MB Ideone Link

#include <stdio.h>
void f()
{
    int a[63500000];
}

int main()
{
    f();
    return 0;
}

Please explain why there is difference in memory used or my concept of memory allocation is wrong ??

请解释为什么使用的内存有差异或者我的内存分配概念是错误的?

3 个解决方案

#1


25  

First of all: the ideone compiler is GCC.

首先:ideone编译器是GCC。

So, what does GCC do when you compile this?:

那么,GCC在编译时会做什么?:

void foo ()
{
  int a[63500000];
}

gcc -S -O2 foo.c generates:

gcc -S -O2 foo.c生成:

foo:
    pushl   %ebp
    movl    %esp, %ebp
    popl    %ebp
    ret

i.e. nothing is allocated on the stack, at all.

即根本没有在堆栈上分配任何东西。

The array is simply optimized away by GCC because it is never used.

该阵列由GCC简单优化,因为它从未使用过。

GCC won't do this with a global, because it is possible that a global is used in another compilation unit, and so it isn't sure that it is never used. Also: The global is not on the stack (since it is a global).

GCC不会对全局执行此操作,因为有可能在另一个编译单元中使用全局,因此不确定它是否从未使用过。另外:全局不在堆栈中(因为它是全局的)。

Now, lets see what happens when you actually use the local array:

现在,让我们看看实际使用本地数组时会发生什么:

int bar (int a, int b, int c)
{
  int f[63500000];
  f[a] = 9;
  f[b] = 7;
  return f[c];
}

Things are very different:

情况非常不同:

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

This line: subl $254000000, %esp corresponds to the size of the array. i.e. memory is allocated on the stack.

此行:subl $ 254000000,%esp对应于数组的大小。即,在堆栈上分配存储器。

Now, what if I tried to use the bar function in a program:

现在,如果我尝试在程序中使用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);
}

We already saw, that the bar function allocates 250 or so megabytes on the stack. On my default GNU/Linux install, the stack size is limited to 8MB. So when the program runs, it causes a "Segmentation fault". I can increase it if I want, by executing the following in a shell:

我们已经看到,bar函数在堆栈上分配250左右的兆字节。在我的默认GNU / Linux安装中,堆栈大小限制为8MB。因此,当程序运行时,会导致“分段错误”。如果我愿意,可以通过在shell中执行以下命令来增加它:

ulimit -s 1000000 #i.e. allow stack size to grow close to 1GB

Then I can run the program, and it will indeed run.

然后我可以运行该程序,它确实会运行。

The reason why it fails on the ideone website is that they have limited the stack size when executing programs (and they should, otherwise malicious users could mess up their system).

它在ideone网站上失败的原因是它们在执行程序时限制了堆栈大小(并且它们应该,否则恶意用户可能会搞乱他们的系统)。

#2


5  

Cases 2, 3

案例2,3

Variables that you define inside functions are allocated on the stack. That means that the associated memory is cleaned up (the stack is "popped") when the function exits.

您在函数内定义的变量将在堆栈中分配。这意味着当函数退出时,相关的内存被清除(堆栈被“弹出”)。

Case 1

Variables defined in global scope are allocated in a data segment (or, generally, a memory space requested from the operating system) that exists for the lifetime of the process.

在全局范围中定义的变量在数据段(或通常是从操作系统请求的存储空间)中分配,该数据段在进程的生命周期中存在。

Additionally

Memory allocated using malloc is allocated from a heap and remains allocated until explicitly released using free.

使用malloc分配的内存是从堆中分配的,并保持分配,直到使用free明确释放。

Note that a modern OS may well provide address space requested by a program, but not physically back that address space with RAM until the memory (or a portion of the memory often called a page) is physically accessed.

注意,现代OS可能很好地提供程序所请求的地址空间,但是在物理*问存储器(或通常称为页面的存储器的一部分)之前,物理上不用RAM支持该地址空间。

#3


2  

case 2 and case 3 would result in stack overflow as you are asking for 64 MB of stack memory wherein your stack is typically 8 MB on Linux . this would result in random bad things and /or core dumps and crashes.

情况2和情况3会导致堆栈溢出,因为您要求64 MB的堆栈内存,其中您的堆栈通常在Linux上为8 MB。这会导致随机坏事和/或核心转储和崩溃。

this answer greatly explains various sections of process address space (.text, .bss , .data )and how various allocations of variables is done.

这个答案极大地解释了进程地址空间的各个部分(.text,.bss,.data)以及如何进行各种变量分配。

#1


25  

First of all: the ideone compiler is GCC.

首先:ideone编译器是GCC。

So, what does GCC do when you compile this?:

那么,GCC在编译时会做什么?:

void foo ()
{
  int a[63500000];
}

gcc -S -O2 foo.c generates:

gcc -S -O2 foo.c生成:

foo:
    pushl   %ebp
    movl    %esp, %ebp
    popl    %ebp
    ret

i.e. nothing is allocated on the stack, at all.

即根本没有在堆栈上分配任何东西。

The array is simply optimized away by GCC because it is never used.

该阵列由GCC简单优化,因为它从未使用过。

GCC won't do this with a global, because it is possible that a global is used in another compilation unit, and so it isn't sure that it is never used. Also: The global is not on the stack (since it is a global).

GCC不会对全局执行此操作,因为有可能在另一个编译单元中使用全局,因此不确定它是否从未使用过。另外:全局不在堆栈中(因为它是全局的)。

Now, lets see what happens when you actually use the local array:

现在,让我们看看实际使用本地数组时会发生什么:

int bar (int a, int b, int c)
{
  int f[63500000];
  f[a] = 9;
  f[b] = 7;
  return f[c];
}

Things are very different:

情况非常不同:

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

This line: subl $254000000, %esp corresponds to the size of the array. i.e. memory is allocated on the stack.

此行:subl $ 254000000,%esp对应于数组的大小。即,在堆栈上分配存储器。

Now, what if I tried to use the bar function in a program:

现在,如果我尝试在程序中使用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);
}

We already saw, that the bar function allocates 250 or so megabytes on the stack. On my default GNU/Linux install, the stack size is limited to 8MB. So when the program runs, it causes a "Segmentation fault". I can increase it if I want, by executing the following in a shell:

我们已经看到,bar函数在堆栈上分配250左右的兆字节。在我的默认GNU / Linux安装中,堆栈大小限制为8MB。因此,当程序运行时,会导致“分段错误”。如果我愿意,可以通过在shell中执行以下命令来增加它:

ulimit -s 1000000 #i.e. allow stack size to grow close to 1GB

Then I can run the program, and it will indeed run.

然后我可以运行该程序,它确实会运行。

The reason why it fails on the ideone website is that they have limited the stack size when executing programs (and they should, otherwise malicious users could mess up their system).

它在ideone网站上失败的原因是它们在执行程序时限制了堆栈大小(并且它们应该,否则恶意用户可能会搞乱他们的系统)。

#2


5  

Cases 2, 3

案例2,3

Variables that you define inside functions are allocated on the stack. That means that the associated memory is cleaned up (the stack is "popped") when the function exits.

您在函数内定义的变量将在堆栈中分配。这意味着当函数退出时,相关的内存被清除(堆栈被“弹出”)。

Case 1

Variables defined in global scope are allocated in a data segment (or, generally, a memory space requested from the operating system) that exists for the lifetime of the process.

在全局范围中定义的变量在数据段(或通常是从操作系统请求的存储空间)中分配,该数据段在进程的生命周期中存在。

Additionally

Memory allocated using malloc is allocated from a heap and remains allocated until explicitly released using free.

使用malloc分配的内存是从堆中分配的,并保持分配,直到使用free明确释放。

Note that a modern OS may well provide address space requested by a program, but not physically back that address space with RAM until the memory (or a portion of the memory often called a page) is physically accessed.

注意,现代OS可能很好地提供程序所请求的地址空间,但是在物理*问存储器(或通常称为页面的存储器的一部分)之前,物理上不用RAM支持该地址空间。

#3


2  

case 2 and case 3 would result in stack overflow as you are asking for 64 MB of stack memory wherein your stack is typically 8 MB on Linux . this would result in random bad things and /or core dumps and crashes.

情况2和情况3会导致堆栈溢出,因为您要求64 MB的堆栈内存,其中您的堆栈通常在Linux上为8 MB。这会导致随机坏事和/或核心转储和崩溃。

this answer greatly explains various sections of process address space (.text, .bss , .data )and how various allocations of variables is done.

这个答案极大地解释了进程地址空间的各个部分(.text,.bss,.data)以及如何进行各种变量分配。