12

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

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

#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

#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 ??

Snehasish
  • 1,051
  • 5
  • 20
  • 37
  • 1
    You know, you should post code directly in the answer instead of giving Ideone links – ApprenticeHacker Aug 15 '12 at 21:10
  • How do you *know* that this is how much memory the programs consume? – ArjunShankar Aug 15 '12 at 21:13
  • 1
    In your local array examples, you don't actually use most of the array, so compiler could safely optimize it out. – TJD Aug 15 '12 at 21:14
  • @ArjunShankar Sir, whenever we compile a program in ideone it shows the time required and memory used by the program. – Snehasish Aug 15 '12 at 21:17
  • @Snehasish - I'd rather not be referred to as 'sir'. Neither would anyone else here on SO. None of us are knights, and we're all equal. As to the 1.6MB, it really has *nothing* to do with the size of the array at all. If you see [this example with an array of 1 element](http://ideone.com/1a7A1), its *still* around 1.6MB. Actually the entire array is optimized away by GCC because it's not used. You can see that from [the assembly produced with `gcc -S`](http://pastebin.com/szrRMmeF) – ArjunShankar Aug 15 '12 at 21:23

3 Answers3

26

First of all: the ideone compiler is GCC.

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

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

gcc -S -O2 foo.c generates:

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 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).

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.

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

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:

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).

ArjunShankar
  • 23,020
  • 5
  • 61
  • 83
  • If i try to do memset (a, 0, sizeof(a)) in case 2 and case 3, why does SIGSEV exception is thrown ? – Snehasish Aug 15 '12 at 21:47
  • @Snehasish - Look at the last bit of my answer. I have edited it. It's because of the stack size limit (this is a limit set by the operating system) – ArjunShankar Aug 15 '12 at 21:49
  • +1 for explaining the optimized out version, which doesn't result in stack overflow. – Jay D Aug 16 '12 at 22:21
8

Cases 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.

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.

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • If I try to do memset(a, 0, sizeof(a)) in case 2 and case 3 segmentation fault occurs. Why ? – Snehasish Aug 15 '12 at 21:29
  • About case 2 and 3, the memory isn't allocated on the stack at all. Ever. It is simply optimized away by GCC. You can see why here: http://ideone.com/1a7A1 i.e. The 250MB array example by OP, and this 4 byte example, both use almost the same amount of memory, as reported by ideone. – ArjunShankar Aug 15 '12 at 22:04
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.

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

Community
  • 1
  • 1
Jay D
  • 3,263
  • 4
  • 32
  • 48