c/c++后台开发必知堆与栈的区别

堆(Heap)与栈(Stack)是开发人员必须面对的两个概念 , 在理解这两个概念时 , 需要放到具体的场景下 , 因为不同场景下 , 堆与栈代表不同的含义 。 一般情况下 , 有两层含义:(1)程序内存布局场景下 , 堆与栈表示两种内存管理方式;(2)数据结构场景下 , 堆与栈表示两种常用的数据结构 。
1.程序内存分区中的堆与栈1.1 栈简介栈由操作系统自动分配释放, 用于存放函数的参数值、局部变量等 , 其操作方式类似于数据结构中的栈 。 参考如下代码:
int main() { int b;//栈 char s[] = "abc";//栈 char *p2;//栈}其中函数中定义的局部变量按照先后定义的顺序依次压入栈中 , 也就是说相邻变量的地址之间不会存在其它变量 。 栈的内存地址生长方向与堆相反 , 由高到底 , 所以后定义的变量地址低于先定义的变量 , 比如上面代码中变量 s 的地址小于变量 b 的地址 , p2 地址小于 s 的地址 。 栈中存储的数据的生命周期随着函数的执行完成而结束 。
1.2 堆简介堆由开发人员分配和释放 ,若开发人员不释放 , 程序结束时由 OS 回收 , 分配方式类似于链表 。 参考如下代码:
int main() { // C 中用 malloc() 函数申请 char* p1 = (char *)malloc(10); cout<<(int*)p1<其中 p1 所指的 10 字节的内存空间与 p2 所指的 10 字节内存空间都是存在于堆 。 堆的内存地址生长方向与栈相反 , 由低到高 , 但需要注意的是 , 后申请的内存空间并不一定在先申请的内存空间的后面 , 即 p2 指向的地址并不一定大于 p1 所指向的内存地址 , 原因是先申请的内存空间一旦被释放 , 后申请的内存空间则会利用先前被释放的内存 , 从而导致先后分配的内存空间在地址上不存在先后关系 。 堆中存储的数据若未释放 , 则其生命周期等同于程序的生命周期 。
关于堆上内存空间的分配过程 , 首先应该知道操作系统有一个记录空闲内存地址的链表 , 当系统收到程序的申请时 , 会遍历该链表 , 寻找第一个空间大于所申请空间的堆节点 , 然后将该节点从空闲节点链表中删除 , 并将该节点的空间分配给程序 。 另外 , 对于大多数系统 , 会在这块内存空间中的首地址处记录本次分配的大小 , 这样 , 代码中的delete语句才能正确地释放本内存空间 。 由于找到的堆节点的大小不一定正好等于申请的大小 , 系统会自动地将多余的那部分重新放入空闲链表 。
1.3 堆与栈区别堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式 , 主要有如下几种区别:(1)管理方式不同 。 栈由操作系统自动分配释放 , 无需我们手动控制;堆的申请和释放工作由程序员控制 , 容易产生内存泄漏;
(2)空间大小不同 。 每个进程拥有的栈的大小要远远小于堆的大小 。 理论上 , 程序员可申请的堆大小为虚拟内存的大小 , 进程栈的大小 64bits 的 Windows 默认 1MB , 64bits 的 Linux 默认 10MB;
(3)生长方向不同 。 堆的生长方向向上 , 内存地址由低到高;栈的生长方向向下 , 内存地址由高到低 。
(4)分配方式不同 。 堆都是动态分配的 , 没有静态分配的堆 。 栈有2种分配方式:静态分配和动态分配 。 静态分配是由操作系统完成的 , 比如局部变量的分配 。 动态分配由alloca函数进行分配 , 但是栈的动态分配和堆是不同的 , 他的动态分配是由操作系统进行释放 , 无需我们手工实现 。
(5)分配效率不同 。 栈由操作系统自动分配 , 会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址 , 压栈出栈都有专门的指令执行 , 这就决定了栈的效率比较高 。 堆则是由C/C++提供的库函数或运算符来完成申请与管理 , 实现机制较为复杂 , 频繁的内存申请容易产生内存碎片 。 显然 , 堆的效率比栈要低得多 。
(6)存放内容不同 。 栈存放的内容 , 函数返回地址、相关参数、局部变量和寄存器内容等 。 当主函数调用另外一个函数的时候 , 要对当前函数执行断点进行保存 , 需要使用栈来实现 , 首先入栈的是主函数下一条语句的地址 , 即扩展指针寄存器的内容(EIP) , 然后是当前栈帧的底部地址 , 即扩展基址指针寄存器内容(EBP) , 再然后是被调函数的实参等 , 一般情况下是按照从右向左的顺序入栈 , 之后是被调函数的局部变量 , 注意静态变量是存放在数据段或者BSS段 , 是不入栈的 。 出栈的顺序正好相反 , 最终栈顶指向主函数下一条语句的地址 , 主程序又从该地址开始执行 。 堆 , 一般情况堆顶使用一个字节的空间来存放堆的大小 , 而堆中具体存放内容是由程序员来填充的 。