4

I was reading this article and saw this: "This article assumes that you already know and understand at least basically how the memory map in GNU/Linux system works, and specially the difference between memory statically allocated in the stack and memory dynamically allocated in the heap."

This confused me because I thought that stack and heap are dynamically allocated, meaning only allocated if necessary, and global variables and variables declared as "static" inside of a function are statically allocated, meaning always allocated.

For example, if I have

void f() {
    int x = 1;
    ...
}

the value 1 only gets put on the stack and the stack pointer only gets incremented if the function f() gets called. Likewise, if I have

void f() {
    int x = malloc(1 * sizeof(int));
    ...
}

that heap memory only gets allocated if f() is called. However, if I have "int x = 1;" in the global section of the program or "static int x = 1;" within a function body, any time I run this program, that memory will be allocated in the data section with the value 1.

Am I wrong about any of this?

trincot
  • 317,000
  • 35
  • 244
  • 286
random_stuff
  • 197
  • 2
  • 12
  • 2
    Static variables are never allocated on the stack. – teppic Oct 10 '15 at 17:43
  • Technically local variables doesn't have to be on the stack, there might not even be a stack. In fact, the C specification doesn't mention a stack in the context of local variables or arguments, it just specifies the scope and lifetime of local variables. – Some programmer dude Oct 10 '15 at 17:48
  • That's true, a local variable might end up being just a register (no stack use necessary). But assuming that it does go on the stack, is it right to call that "static allocation"? – random_stuff Oct 10 '15 at 17:49
  • Static variables exist for the life of the program. The stack (as above, nothing to do with C) is designed for temporary variables only. – teppic Oct 10 '15 at 17:53

3 Answers3

4

The stack itself is statically allocated. Variables allocated in the stack come and go, as control flow enters and leaves their scope.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Not sure if I can technically accept this as the correct answer (because I have no idea of how to verify), but it makes the most sense! – random_stuff Oct 10 '15 at 17:52
  • @loren: there is one stack. It is given a fixed memory allocation before `main` is entered. It is never relocated, and it exists until after `main` has terminated. How more static can you be? – rici Oct 10 '15 at 17:56
  • By the way, accepting the answer means it satisfied you, nothing more. Other people can indicate agreement and disagreement with their votes. You don't need a court order or a Ph.D. to indicate that an answer helped you, if it did. – rici Oct 10 '15 at 17:59
  • Yes, but the text I'm reading makes it sound like variables on the stack (not the stack itself) are "statically allocated" which makes no sense to me. – random_stuff Oct 10 '15 at 18:00
  • @loren: it doesnt say anything about variables. It refers to the memory allocated *to the stack*. That memory cannot leak. – rici Oct 10 '15 at 18:03
  • @rici: Historically, on many systems, the stack didn't occupy a fixed range of memory but would instead grow down from the top of memory while the heap would grow up from the bottom. If the stack and heap collided, the system would crash, but if a program which had 50K of stack+heap space could use 40K of stack space if it never used more than 10K of heap, or 40K of heap space if it never used more than 10K of stack, so I wouldn't call the stack allocation "static". – supercat Oct 05 '16 at 16:13
  • As you mentioned in the comment, if the stack is given a fixed memory before `main` is entered, why does stack overflow happen? Stack "grows up" during *runtime*. Am I wrong? – starriet Feb 22 '22 at 16:41
  • @starriet: Stack overflow happens when the stack can't (or doesn't) grow any more :-) It's upper (or lower, depending on which direction it grows) limit is not exactly fixed, but I don't think that's relevant. Not all of the address range allocated to the stack is actually mapped onto real memory, but I don't think that's relevant either. As supercat explains above, the sbrk call can steal a range of memory (addresses) from the stack and give them to the heap, but there is no call which expands the range of addresses allocated to the stack. And until sbrk is called, that range is in the stack. – rici Feb 22 '22 at 17:58
  • 1
    @starriet: I'm not sure where your confusion here comes from. If I allocated a fixed-size string buffer, and start reading into it from a file, I could eventually overflow that buffer. At runtime. The buffer was allocated at compile time and overrun at runtime. Is that surprising? A stack is no different. You can't tell at compile time how many times a recursive function will be called (or how deep the call stack is, regardless of recursion), and so you can't tell how much stack space will be used by the program *until it actually runs*. – rici Feb 22 '22 at 18:02
  • @rici You mentioned the exact point my confusion came from. - *"you can't tell how much stack space will be used by the program until it actually runs."* - This is totally true. Then how can stack be *statically* allocated and how can it be given a *fixed* memory allocation before `main` is entered? Shouldn't we say "the stack is *dynamically* allocated during runtime"? Because stack size can be determined only when the program actually runs. Btw, thank you very much for your comments :) – starriet Feb 23 '22 at 02:16
  • 1
    @starriet: You can't tell how much space the buffer might need, but nothing stops you from from declaring it static. The point is that static storage occupies a reserved range of addresses, but nothing forces the program to use all of it. It's just there, waiting to be used if needed. And so with the stack. Because, and this is crucial: *the stack cannot be moved*. So it is where it is (virtually speaking). That's static. If you dynamically reallocated the input buffer every time you read a block, it wouldn't overflow, but it might move. That's dynamic. – rici Feb 23 '22 at 02:29
  • 1
    What happens with the stack at runtime, at least on some operating systems, is that not all stack's address range is actually mapped to real memory until an attempt is made to reference it. But don't let that confuse you. The addresses are still reserved to the stack.Optimistic mapping of virtual storage is a trick used to compensate for the fact that the stack cannot be moved. It's a cool trick. But it's not dynamic allocation, in the strict sense of the word. (And it applies equally to any uninitialised block of static storage.) – rici Feb 23 '22 at 02:31
  • 1
    Oh, yeah. One other thing. Thread stacks are generally actually dynamically allocated, because they only live as long as the thread does. Once the thread ends, its stack is dead and the memory can be returned to the memory manager. Start a new thread, and you might or might not get the same memory addresses, because it's dynamic. The same with thread_local storage for that thread. But the main program's stack is not like that. It lasts from when you load the program until when the program terminates. Just the same as the (rest of) the program's static data. – rici Feb 23 '22 at 02:39
  • 1
    But where the thread stack is the same as the main stack is that it cannot be reallocated because it cannot be moved. So even though it's a dynamic allocation, it has a fixed size and if you exceed it, you're toast. When you write threaded code, you have to be aware of that. – rici Feb 23 '22 at 02:42
  • @rici Thank you again for the detailed comments! Let me describe what I understood so far. When we run a program, *OS* allocates the *fixed-size* of memory *to* a program so that the program can use some part of that memory as a stack. So we can say the 'OS' (not the program) allocates the stack statically(actually the whole memory the program can use is allocated statically by the OS). – starriet Feb 24 '22 at 07:49
  • @rici After the program starts, it uses some part of the allocated memory as a stack. So we can say that the stack is allocated 'statically' by the 'OS'(the whole allocated memory has fixed size), and the stack is used 'dynamically' by the 'program' during the runtime. And if the program uses all the allocated memory, which is fixed-size, then stack overflow or heap overflow can happen. – starriet Feb 24 '22 at 07:53
  • @rici So, some people say the stack is allocated 'statically' because they are talking about the memory allocation by the 'OS'. But some people say the stack is allocated 'dynamically' because they are talking about the memory consumption by the 'program'. Did I understand correctly? – starriet Feb 24 '22 at 07:56
4

Static variables are initialized only once, even if the initialization statement is inside of a function body.

Check the wikipedia example:

#include <stdio.h>

void func() {
    static int x = 0; 
    /* x is initialized only once across five calls of func() and
      the variable will get incremented five 
      times after these calls. The final value of x will be 5. */
    x++;
    printf("%d\n", x); // outputs the value of x
}

int main() { //int argc, char *argv[] inside the main is optional in the particular program
    func(); // prints 1
    func(); // prints 2
    func(); // prints 3
    func(); // prints 4
    func(); // prints 5
        return 0;
}

The stack is basically a large statically allocated array with a movable pointer that starts at the beginning of it. When you call a function (starting w/ main), the pointer moves (creates a stack frame) and the space in the stack frame is sliced up and given to local variables (how many local variables you have determines how big your function's stack frame will be). So local variables are kind of dynamic (they only emerge once you enter the function), but the stack is of a static size. If you allocate a super large structure on it or use too much recursion, you'll go past the end and the OS will take you down—a phenomenon known as stackoverflow. ( The stackoverflow icon icon actually illustrates this. The gray container at the bottom represents the static array that the stack is. The orange rectangles are frames created by function calls. As in a proper stack overflow, the frames overflow the container and boom -- you're program is dead. The fact that the frames go up illustrates another, rather special thing about the stack—new frames have lower addresses than the old ones so stackoverflows really happen at the beginning of the stack array rather than the end of it (unless you think of arrays as starting at their largest index and ending at 0). )

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • *"...but the stack is of a static size"* - Isn't a total stack size determined at runtime? If it's determined at compile time, why does stack overflow happen during runtime? – starriet Feb 22 '22 at 16:36
2

Stack is allocated in unit of stack frame.

  • When a function is called, a stack frame is allocated for it,
  • When a function returns, its stack frame disappear,

And, stack helps to store function arguments & local variables.

After a function get its stack frame, yes, within the stack frame the function use bytes of it as need dynamic.


Dynamic allocate stack like heap

If u want to allocate memory on stack like the way as heap, then you can use alloca() from <alloca.h>, it's quicker than heap, but in most case u don't need that, it has disadvantages, thus not suggested in general case.


Describe stack allocation in different context might make it more clear:

  • From the view of a linux thread, (by the way, each process has 1 thread on creation by default, as main thread), the stack is of fix size & allocated on thread creation, (2Mb for IA-32, 32Mb for IA-64, by default), and you can change the default size as need. So you can say this is fix, and static.
  • From the view of a function within thread or process, the stack frame is allocated for it from the thread's stack memory when the function starts, and the stack frame disappear when the function finish.
  • From the view of a non-static local variable inside a function, the variable is allocated from the stack frame of the function as need, dynamically.

So, should it be called static or dynamical, you decide.

Eric
  • 22,183
  • 20
  • 145
  • 196
  • Right, but is that still called "static"? – random_stuff Oct 10 '15 at 17:42
  • @LorenLugosch If a local variable is declared as `static` within a function, then it is not stored in the stack frame, instead it is stored in the `initialized data segment` or `ininitialized data segment`, so that the value won't lose between function calls. In this case, yes the variable is static, but it is not on the stack frame. This is about the c `static` keyword. – Eric Oct 10 '15 at 17:56
  • That is true, but the question is not about the nature of local variables declared as "static" (which I know to be statically allocated), but rather the nature of local variables which go on the stack. The question is: is it right to call stack memory "statically allocated"? – random_stuff Oct 10 '15 at 17:59