Stack area and heap area memory allocation

The following is a detailed analysis of the difference between stack area and heap area memory allocation, friends who need it can come and refer to

I have always had a vague understanding of this problem. I believe that many of my friends are like this. I always hear that memory is allocated on the stack and then on the heap. So what is the difference between them? ? To illustrate this problem, let's first look at the internal organization of the memory.

As can be seen from the above figure, the memory occupied by the program is divided into the following parts.

1. The stack area (stack)
is automatically allocated and released by the compiler, storing function parameter values, local variable values, etc. The memory allocation is continuous, similar to what we usually call stack. If it is not clear, then It is thought of as an array, and its memory allocation is continuous allocation, that is, the allocated memory is in a continuous memory area. When we declare variables, the compiler will automatically allocate memory following the end of the current stack area.

2. The heap is
generally allocated and released by the programmer. If the programmer does not release it, the operating system may reclaim it when the program ends. Similar to the linked list, the distribution in the memory is not continuous. They are the memory blocks in different areas linked by pointers. Once a node is disconnected from the chain, we must artificially release the disconnected node from the memory.

3. Global area (static area) (static)
The storage of global variables and static variables are placed together, initialized global variables and static variables are in one area, uninitialized global variables and uninitialized static variables are adjacent Another area. Released by the system after the program ends

4. Text constant area The
constant string is placed here. Released by the system after the program ends

5. Program code area
Store the binary code of the function body.

Let's look at an example first.
char c; //allocate on the stack
char *p = new char[3]; //allocate on the heap, assign the address to p;

When the compiler encounters the first instruction, it calculates its size, and then finds that the space of the current stack is greater than the size of the allocated space. If the space in the stack is larger than the requested space, then allocate memory space for it , Note: Here, the allocation of inner space is continuous, and it is allocated after the last allocation. If the space in the stack is less than the size of the requested space, then the system will reveal the stack overflow at this time and give the corresponding exception information.

When the compiler encounters the second instruction, since p is allocated on the stack, it is the same as the above method when allocating internal space for p, but when it encounters the new keyword, then the compiler knows that this is the user The requested dynamic memory space will be transferred to the heap to find space allocation for it. Attention everyone: the memory space on the heap is not contiguous, it is connected by the corresponding linked list to the inner block of its space area, so after receiving the designation of allocating memory space, it will not immediately allocate the corresponding Space, but to calculate the required space first, and then go through the entire heap (ie, through the nodes of the entire chain), and allocate the memory block encountered for the first time to it. Finally, assign the first address of the character array allocated on the heap to p. At this time, everyone has already understood that the first address of the character array applied for in the heap is stored in p, which is the first address applied for in the heap. The address of the array is now assigned to the pointer variable p. In order to illustrate the problem more vividly, please see the picture below:

As can be seen from the above figure, the first address of the array we dynamically allocated on the heap is stored in the content pointed to by the pointer p.

Please note : the memory space applied for on the stack, when we go out of the scope of the variable, the system will automatically reclaim these spaces, and the space applied for on the heap, when the corresponding scope is out, we need Explicitly call delete to release the requested memory space. If we do not release these spaces in time, there will be more and more memory fragments in the memory, so our actual memory space will become more and more. Less, that is, more and more isolated memory blocks. Here, we know that the memory area in the heap is not continuous, or the effective memory area is connected through a linked list pointer. If we apply for a certain piece of memory, then this memory area will be continuous (connected through the linked list) The memory block is disconnected. If we do not release it in time after using it, it will be isolated. Since there is no pointer to it, this area will become a memory fragment. After using the dynamically allocated memory (applied through NEW), you must explicitly delete it. For this, we must remember. . .

I have stated the concepts between them above. As for the comparison between the two of them, I can’t make them intermittently here. For this issue, an article by a netizen on the Internet explains in more detail, and it also has professional colors. , The following article is a partial fragment.


Application size limit
Stack
: In Windows, the stack is a data structure extended to lower addresses, and is a contiguous memory area. This sentence means that the address at the top of the stack and the maximum capacity of the stack are pre-defined by the system. Under WINDOWS, the size of the stack is 2M (some say it is 1M, in short, it is a constant determined at compile time). When the requested space exceeds the remaining space of the stack, overflow will be prompted. Therefore, the space available from the stack is smaller.

Heap : Heap is a data structure that extends to high addresses and is a discontinuous memory area. This is because the system uses a linked list to store free memory addresses, which are naturally discontinuous, and the traversal direction of the linked list is from low addresses to high addresses. The size of the heap is limited by the effective virtual memory in the computer system. It can be seen that the space obtained by the heap is more flexible and larger.

申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。

堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。
堆和栈中的存储内容
: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

存取效率的比较
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";

aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。

比如:

复制代码
1 void main()
2 {
3     char a = 1;
4     char c[] = "1234567890";
5     char *p ="1234567890";
6     a = c[1];
7    a = p[1];
8     return;
9 }
复制代码

对应的汇编代码

复制代码
1 10: a = c[1];
2 00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
3 0040106A 88 4D FC mov byte ptr [ebp-4],cl
4 11: a = p[1];
5 0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
6 00401070 8A 42 01 mov al,byte ptr [edx+1]
7 00401073 88 45 FC mov byte ptr [ebp-4],al
复制代码

第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。 

小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。

使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度

Guess you like

Origin blog.csdn.net/qq_38204688/article/details/76854710