2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 堆与栈的总结(own)

堆与栈的总结(own)

时间:2018-08-29 23:05:03

相关推荐

堆与栈的总结(own)

一般一个应用程序在内存中的存放会分多个数据区域:

├———————┤低端内存区域

│……│

├———————┤

│动态数据区│

├———————┤

│……│

├———————┤

│代码区│

├———————┤

│静态数据区│

├———————┤

│……│

├———————┤高端内存区域

而其中的动态数据区就是堆和栈的存放区域。虽然堆和栈都归于动态数据存储区域,但是他们本身还是有区别的。

1. 内存分配方式不同

栈:由编译器自动分配的内存,不需要程序自己分配。但是栈本身大小是有限的。

堆:由程序运行时动态分配,同时要注意手动回收。其大小视虚拟内存大小而定。

2.内存的存储地址生长方向不同

栈:在内存中由高地址向低地址延生。

堆:在内存中由低地址向高地址延生。

3.数据的存储不一样

栈:其数据在内存中是线性连续的。

堆:其数据存储是不连续的,可以认为是链表的形式分配和存储。

总体而言:栈的使用有限制,我们只能申请,不能管理。而堆相对就自由很多,可以随时申请和管理内存数据。但是堆的过多使用会自然引入内存碎片,因为其存储是不连续的,同时不及时回收会导致内存泄露和内存不足。另一方面,由于堆内存的申请要耗费更多的时间,因此效率其实是不高的。在实际使用中需要尽量少用堆的申请。

栈的重要作用:栈一般用来存储临时变量,也就是函数中的局部变量。另外的一个重要作用就是存储代码运行的内存地址,也就是可以保存一个函数运行的现场。

假设调用函数为:

int func(int para1, int para2)

{

int var1;

int var2;

var1 = para2;

var2 = para1;

return 0;

}

则调用这个函数引起的栈变化如下:

├———————┤高端内存区域 (ebp栈底,保存现场)

|-------para2--------| 最右边的参数

|---------para1------| 一次向左移动,压入参数

|--------ret-----------| 函数调用返回的地址(esp),之后开始跳到func运行

|----------------------| 继续将此函数的ebp压栈,保存现场,并用esp代替(至少unix是这样)

|---------var2--------| 内部变量

|----------var1-------| 内部变量

|....执行代码.........|

|-----------------------| 低端内存区域(esp栈顶)

我们可以看到首先会压入函数传入的参数,并且是从最右边开始压入,依次向左。然后压入这个函数的返回地址,接着开始跳转到该函数执行。在执行代码之前,会再次将ebp压栈并用esp代替,保存现场。然后开始压入函数的临时变量,最后开始执行代码。在执行完之后会依次向上出栈(pop)。当回到最初的ebp栈基时再从eip中取得下一个执行指令开始往下执行。

从上述我们可以预见,如果一个函数递归调用本身而无法返回,则栈会无限延伸下去,直到栈溢出,这严重的话肯恩会导致系统崩溃。同时如果函数返回值被修改,则出栈的时候无法找到正确的返回地址,一样会导致问题。所以使用时候需要多加注意。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。