Stack, heap and dynamic memory allocation

梦想的初衷 提交于 2019-12-13 08:15:24

问题


I have some confusion about these three concepts: Stack, Heap, and Dynamic memory allocation. I'll provide examples in C++.

  1. Am I correct to say that given a program, for all its variables, arrays, and maybe objects on stack, when the program just starting, all the memory space needed is already there, so everything is predetermined? But when the program is running, for me it still sounds like "dynamic" since a stack is still changing in a sense that values are still push into, pop off the stack, on the runtime.

  2. Regarding to heap, for the "dynamic" sense, I brought the idea from some answer on this site, it's for something determined on runtime:

    cin >> box_size;
    int *box = new int[box_size];
    

    But, then how about this:

    Box surprise_box = new Box();
    

    I already know how much space it's needed on compile time right? But it's still on the heap. So it seems like "Dynamic" memory allocation is just about the burden of allocation/deallocation of memory becomes one of programmer's.

†: It should be Box *ptr_surprise_box = new Box(); instead. (Thanks for the comment)


I understand why my question is considered too broad, but I don't know how to split them into pieces. Even worse, now I'm considering whether this has something to do with address space and those memory address determined in compile time.


回答1:


  1. Generally speaking, yes. At the beginning of your program, most of the data is on stack when you call a function, then you can allocate memory on heap. (Well, there is not only stack or heap in a program, there may be also global variables in other segments, it is a long story).

The stack space is allocated by compiler, when you enter a function, the compiler generated code allocates enough space for the stack variables automatically.

The heap space is allocated by you, when you need some memory, you call a function to allocate heap space for you.

  1. The pointer to an address of memory is a variable on stack

For your code:

cin >> box_size;
int *box = new int[box_size];

Here box is a variable on stack. The value of box variable is a pointer to the memory on heap.

But Box surprise_box = new Box(); is not valid syntax.

Examples:

  • Box box1;: the variable box1 is on stack.

  • Box *box2 = new Box();: the variable of box2 is on stack, it is a pointer, points to the memory of new Box()

Updated:

There is no clear "dynamic" definition with "heap" and "stack" concept. For example, in C99, if you do scanf("%d", &size); int a[size]; it is still OK and a can be on stack, not heap. It all depends on the compiler's behavior. Memory allocated by you is usually on heap (you called memory allocation functions, including new()), memory allocated by the compiler's code is usually on stack.

ps: I think @Slava's answer is quite good. These conepts are in different fields. stack and heap are mainly OS-related, dynamic and static are mainly language-related. I just talked about the most implementations of the modern C++ language, they happened to put new() memory into heap, etc.




回答2:


I have some confusion about these three concepts: Stack, Heap, and Dynamic memory allocation.

Of course you are, you mixed concepts from different area - first 2 are related to OS, last on to the language.

For C++ there is no such thing as stack or heap. There are 4 different storage durations for objects in C++: automatic, static, thread and dynamic. Yes objects with automatic storage duration are usually stored in stack and ones with dynamic in heap, but that is details of implementations - from language point of view there are no such things. Details about storage duration can be found here




回答3:


I find that best way to look at heap vs. stack, is not in terms of "dynamic" or "knowing the size at compile time", (though, those can be factors). Instead, it is best to view them in terms of lifetime management.

Things allocated on the stack are destroyed when they go out of scope. Things allocated on the heap will exist until they are explicitly freed with a delete, free, or delete[] (depending on how they are allocated).

To answer your questions:

Am I correct to say that given a program, for all its variables, arrays, and maybe objects on stack, when the program just starting, all the memory space needed is already there, so everything is predetermined.

Eh, on a per-function basis, kinda..., but this view doesn't really account for the fact that functions can do things like calling themselves (recursion) and reach arbitrary stack size usage.

So it seems like "Dynamic" memory allocation is just about the burden of allocation/deallocation of memory becomes one of programmer's.

Yes, the fundamental difference is really all about lifetime management.




回答4:


User slava had mentioned these:

automatic, static, thread and dynamic

I will focus on all but thread. He also stated this:

For C++ there is no such thing as stack or heap


User Even Teran had stated this:

I find that best way to look at heap vs. stack, is not in terms of "dynamic" or "knowing the size at compile time", (though, those can be factors). Instead, it is best to view them in terms of lifetime management.

Things allocated on the stack are destroyed when they go out of scope. Things allocated on the heap will exist until they are explicitly freed with a delete, free, or delete[] (depending on how they are allocated).


I will combine the two previous answers into a single answer with demonstrations:


  • 1st - Automatic Storage

int main () {
    int x = 5;

    { // new scope
        int x = 7;
        std::cout << x << '\n';  // prints 7     
    } // end scope

    std::cout << x << '\n';  // prints 5

    return 0;
}

This is considered Automatic Storage since the variable declarations and memory are destroyed once they go out of scope. You can consider this a stack variable in a sense since in C++ each function has a stack frame. These variables x above both live within main.cpp's stack frame but have automatic storage. However the first call to std::cout will print 7 since it is within the same scope of the 2nd variable declared x. Once the closing brace } is reached this scope is destroyed and so is the 2ndx variable. So when we reach the next call to std::cout this will print 5 because it is within the same scope of the 1st declared x.


  • 2nd - Dynamic Storage

int main() {
   int x = 5;  // Automatic storage
   int* ptr = nullptr; // raw pointer

   ptr = new int(x); // Dynamic Storage
   std::cout << "x = " << x << '\n';        // prints 5
   std::cout << "*ptr = " << *ptr << '\n';  // prints 5

   { // new scope
       *ptr = 12;
   } // end scope

   std::cout << "x = " << x << '\n';        // x unchanged prints 5
   std::cout << "*ptr = " << *ptr << '\n';  // prints 12

   delete ptr; // clean up memory

   return 0;
}

Dynamic Storage lives longer than the scope it is declared in. You can pass dynamic memory from one function to another as long as the original object that it references is still valid otherwise you will have a memory leak, invalid or dangling pointer which can lead the unwanted behavior, undefined behavior, program crash, your OS erased and nuclear bombs going off! (Well the last is a bit dramatic; but don't laugh because poor memory management will reek havoc on your code base and ALL WHO use it!). This allows you to store data and to modify it from one function to another without having to create copies upon copies of it every time you need to reference it in some other calculation.


  • 3rd - Static Storage

static int i = 0; // static storage: life time of application or file scope; similar to a global...

void add1() {
   i++;
}

int main() {
    std::cout << i << '\n';
    add1();
    std::cout << i << '\n';

    for ( int n = 0; n < 10; n++ ) {
        add1();
        std::cout << "n=" << n << ": " << i << '\n';
    }

    return 0;
}

Output

0
1
n=0: 2
n=1: 3
n=2: 4
n=3: 5
n=4: 6
n=5: 7
n=6: 8
n=7: 9
n=8: 10
n=9: 11

Static Storage is a little different. There is no need to clean it up like dynamic memory since it has properties similar to Automatic Storage as it will be destroyed automatically. However, these are typically seen in global namespace or global file space they can be useful, but global variables again can be dangerous if not managed nor used properly. These typically have the lifetime of either the program application if defined in main.cpp or the lifetime of file-scope if defined in some other cpp file. The only other difference with Static Storage is it is also only initialized once, and there is usually only ever one instance of it!


Yes there are different types of storage classes and many still refer to them as stack and heap mainly cause C++ was built off of C; but the meanings and usages have change dramatically over the years. Anymore in C++ it has more to do with the lifetime and visibility of a variable than where it is located in memory.



来源:https://stackoverflow.com/questions/53808955/stack-heap-and-dynamic-memory-allocation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!