数据结构中的堆和栈

栈:一种运算受限的线性表,只允许在表的一端进行插入(入栈)和删除(出栈)操作。所以栈拥有先进后出的特性

同时分为顺序栈以及链式栈两种,顺序栈使用数组作为底层数据结构,链式栈则是链表。

很显然,顺序栈中元素地址连续,链式栈元素地址不连续。

堆:当且仅当满足所有子节点的值总是不大于或者不小于父节点的值的完全二叉树被称之为堆。

父节点大于子节点称为大根堆,反正称为小根堆


堆和栈(内存)

程序的内存分配

栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等,操作方式类似于数据结构中的栈

堆区(heap):一般由人分配释放,若人未释放,程序结束时可能由OS回收,和数据结构的堆是两回事,分配方式类似于链表

全局区(静态区):全局变量和静态变量的存储区域是相同的,未初始化的在相邻的另一块区域,程序结束后由系统释放。

文字常量区:存放常量字符串,系统释放

程序代码区:存放函数体的二进制代码

堆和栈的理论知识

申请方式

栈:系统自动分配

堆:人为申请,并指明大小

申请效率

栈:快,无法人为控制

堆:慢,容易产生内存碎片,导致程序效率降低,但方便

申请后系统的响应

栈:剩余空间大于申请空间即可,否则提示栈溢出

堆:操作系统中有一个记录空闲地址内存的链表,收到申请时从此链表中寻找第一个空间大于申请空间的堆节点,将该节点从此链表中删除,并分配给程序。

大多数系统会在此内存空间的首地址记录本次分配的大小,以便于能正确释放。

此外,由于寻找到的堆节点点不一定等于申请的大小,系统会将多余的放入空闲链表中

申请大小的限制

栈:在Windows下,栈是向低地址拓展的数据结构,是一块连续的内存的区域。

意思是,栈是系统预先规划好的,就那么大,用多了就报错。

堆:向高地址拓展的数据结构,不连续的内存区域,大小受限于计算机系统中有效的虚拟内存。

堆和栈的存储内容

栈:函数调用时,第一个进栈的是函数调用语句的下一条可执行语句的地址,

然后是函数参数,

其次是函数中的局部变量。


堆:一般在头部用一个字节存放堆的大小,堆中具体内容由人决定

总之,栈就像用别人设计的东西,方便但自由度小。

堆就是自己设计制造,麻烦但自由度高。

一些问题

什么是栈,什么是堆(站在实际的计算机物理内存的角度上看)?

栈是为执行线程所留出的内存空间

堆是为动态分配预留的内存空间

每一个线程都有一个栈,每一个应用程序通常只有一个堆

在通常情况下栈由操作系统(OS)和语言的运行时(runtime)控制吗?

当线程创建的时候,操作系统(OS)为每一个系统级(system-level)的线程分配栈。

通常情况下,操作系统通过调用语言的运行时(runtime)去为应用程序分配堆

它们的作用范围是什么?

栈附属于线程,因此当线程结束时栈被回收。

​堆通常通过运行时在应用程序启动时被分配,当应用程序(进程)退出时被回收

它们的大小由什么决定?

当线程被创建的时候,设置栈的大小。

在应用程序启动的时候,设置堆的大小,但是可以在需要的时候扩展(分配器向操作系统申请更多的内存)

哪个更快?

栈比堆要快,因为它存取模式使它可以轻松的分配和重新分配内存(指针/整型只是进行简单的递增或者递减运算),

然而堆在分配和释放的时候有更多的复杂的 bookkeeping 参与。另外,在栈上的每个字节频繁的被复用也就意味着它可能映射到处理器缓存中,所以很快