文章包括以下内容:
- 堆和栈是什么
- 堆和栈的区别
- 程序怎样使用堆和栈
堆和栈是什么
看了很多文章,讲的内容都很多,但关于堆和栈的定义到底是什么?很多是没提及的。
堆和栈是两种不同内存分配方式所获得的
内存区域
的统称。栈是用来存储函数内部临时使用的变量(局部变量),以及函数调用时所用参数的内存区域;堆是用来存储程序运行时的任意数据及对象的内存区域。
堆和栈的区别
分配和释放方式
堆和栈都是在程序运行时所申请分配的。但对于栈中数据的存储和释放是由编译器自动完成的,不需要程序猿参与;而堆的内存空间,是需要在编写的程序中申请分配或释放的(这里针对的是C、C++这样的编程语言;对于Java、Go等编程语言来说,编译器对堆也是有申请分配和回收机制的)。
无论是C还是C++,如果没有在程序中明确的释放堆的内存空间,那么即使在程序中的任务处理完毕后,该内存空间仍会一直残留,这种现象称为
内存泄露
。
分配的效率
栈结构
是系统提供的数据结构,操作系统会在底层对栈提供支持,例如,分配专门的寄存器存放栈的地址,压栈出栈都有专门的执行指令(参照汇编语言中的push、pop),而且栈的内存区域是连续的,这就决定了栈的效率比较高。堆则不同,比如程序想申请一块堆内存,操作系统会遍历记录
空闲内存地址
的链表,寻找第一个空间大于所申请空间的堆节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给该程序。很显然,堆的分配效率比栈要慢的多。
碎片问题
对堆来说,频繁分配和释放(C语言中的 malloc / free)不同大小的堆空间势必会造成内存空间的不连续,从而造成大量碎片,导致程序运行效率降低;而对栈来讲,则不存在这个问题。
内存空间大小问题
由于操作系统是用链表来存储空闲内存地址(内存区域不连续)的,同时链表的遍历方向是由低地址向高地址进行的。因此,堆内存的申请大小受限于计算机系统中有效的虚拟内存。
而栈则不同,它是一块连续的内存区域,其地址的增长方向是向下进行的,向内存地址减小的方向增长。由此可见,栈顶地址、栈的最大容量一般都是由操作系统预先规定好的,如果申请的内存空间超过栈的剩余空间时,将会提示栈溢出错误。相对于堆来说,程序可以从栈中获得的内存空间相对较小。
程序怎样使用堆和栈
这块内容感觉自己理解的不太透彻,就不造作了。
- 可以认真读读《程序是怎样跑起来的》中第九章、第十章
- 还有这篇函数调用栈。
这里说一下,因为高级语言
的代码我们看不出程序对栈的具体操作;机器语言
都是数值序列,我们又看不懂(也许有人可以看懂,😄)。所以只能靠汇编语言了。
参考
- 《程序是怎样跑起来的》
- https://zhuanlan.zhihu.com/p/101531768
- https://article.itxueyuan.com/yeq4Q
- https://zhuanlan.zhihu.com/p/103454656
- http://c.biancheng.net/c/stack/