【转】栈(stuck)和堆(heap)的概念

July 19, 2021 Cpp开发 默认分类

作者:howard
链接:https://www.zhihu.com/question/19729973/answer/390903646
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

首先堆(heap)和栈(stack)两个重名不是翻译问题,而是英文原文就是一样的。
数据结构中堆是满足父子节点大小(比如大根堆中规定父节点的值要比子节点大)关系的一种完全二叉树。由于是完全二叉树,可以用数组来实现,用节点编号来访问和操作节点,简化程序,提升效率。而其大小关系则为我们查询堆中极值提供了常数级别的时间复杂度,又由二叉树的性质,插入和删除则为对数级别时间复杂度。这就好像地位不同的人在排队,排在最前面的一定是地位最高的人,所以堆是优先队列(Priority Queue)实现的基础。
利用这一特性,可以加速某些需要频繁取队列中极值的算法比如 A* 算法等。数据结构中的栈则是一种相当简单的结构。就像是只有一个口的深深的文件桶,先进去的文件会被压在下面(push),而且我们每次只能取到最上面的文件(pop),体现了其先进后出(FILO)的特性。
虽然栈操作简单,但也有如单调栈等在栈内保持一定数据特性的变种。操作系统中的堆和栈都是指内存空间,不同的是堆为按需申请、动态分配,例如 C 中的 malloc 函数和 C++ 中的 new 操作(当然 C++ 的 new 不仅仅是申请内存这么简单)。内存中的空闲空间并不是连续的,而是不同程序占用了不同的一块一块的内存,即使是同一个程序也可能占用了不同地方的多块内存。操作系统中则会对这些空间进行统一的管理,在应用程序提出申请时,就会从堆中按照一定算法找出一块可用内存,标记占用空间等信息之后返回其起始地址给程序。在程序结束之前,操作系统不会删除已经申请的内存,而是要靠程序主动提出释放的请求(free、delete),如果使用后忘记释放,就会造成所谓的内存泄漏问题。因此堆基本上可以理解为当前可以使用的空闲内存,但是其申请和释放都要程序员自己写代码管理。而操作系统的栈则是程序运行时自动拥有的一小块内存,大小在编译期时由编译器参数决定,用于局部变量的存放或者函数调用栈的保存。在 C 中如果声明一个局部变量(例如 int a),它存放的地方就在栈中,而当这个局部变量离开其作用域之后,所占用的内存则会被自动释放,因此在 C 中局部变量也叫自动变量。栈的另一个作用则是保存函数调用栈,这时和数据结构的栈就有关系了。在函数调用过程中,常常会多层甚至递归调用。每一个函数调用都有各自的局部变量值和返回值,每一次函数调用其实是先将当前函数的状态压栈,然后在栈顶开辟新空间用于保存新的函数状态,接下来才是函数执行。当函数执行完毕之后,栈先进后出的特性使得后调用的函数先返回,这样可以保证返回值的有序传递,也保证函数现场可以按顺序恢复。操作系统的栈在内存中高地址向低地址增长,也即低地址为栈顶,高地址为栈底。这就导致了栈的空间有限制,一旦局部变量申请过多(例如开个超大数组),或者函数调用太深(例如递归太多次),那么就会导致栈溢出(Stack Overflow),操作系统这时候就会直接把你的程序杀掉。


作者:思羽
链接:https://www.zhihu.com/question/19729973/answer/13037929
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

个人感觉这里的堆 应该指的是heap而非数据结构中的堆。 栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。区别和联系:1.申请方式 堆是由程序员自己申请并指明大小,在c中malloc函数 如p1 = (char *)malloc(10); 栈由系统自动分配,如声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间2.申请后系统的响应 栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。 堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会 遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内 存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大 小,系统会自动的将多余的那部分重新放入空闲链表中。3.申请大小的限制 栈:在Windows下,栈是向低地址扩展的数据结 构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是 一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。4.申请效率的比较: 栈由系统自动分配,速度较快。但程序员是无法控制的。 堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

添加新评论