程序对内存的使用(分区)
- 栈区(stack):编译器自动分配和释放,相比堆而言较快。存放关于函数的数据,局部变量的值(其实也算函数内的数据)。栈的空间是连续的内存空间。在windows下向低地址扩展。栈是函数调用的基础。操作方式类似于数据结构的栈。(与函数息息相关)
- 堆(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于链表。堆是用来容纳应用程序动态分配的内存区域,当程序使用malloc或new分配内存时,得到的内存来自堆里。堆是向高地址扩展的数据结构,是不连续的内存区域,堆的大小受限于计算机的虚拟内存。因此堆空间获取和使用比较灵活,可用空间较大。
- 静态存储区(static):全局变量和静态变量存放
- 常量区:常量字符串放在此,程序结束后由系统释放。
- 代码区:存放函数体的二进制代码。
栈
栈在存储体系中有很多名称,就比如调用栈(Call Stack),执行栈等等。不过栈是相对于整个系统而言,调用栈(call stack)相对于某个进程而言。
栈的基本信息
功能:栈是函数调用的基础,描述了函数之间的调用关系。具体一点,在函数调用的作用:参数传递、局部变量分配、保存调用的返回地址、保存寄存器以供恢复。
-
栈和栈帧(stack frame):
- 每个进程对应一个栈(stack),在这个进程中每个函数被调用时分别从这个栈占用一段区域,称为帧(frame)。每个栈帧对应一个未执行完的函数。(栈帧是栈的单元)
- 操作方式类似于数据结构的栈。
-
栈帧所含的内容:
- 函数的返回地址和参数:保存当前函数调用前的“断点”信息,也就是函数调用前的指令位置,以便在函数返回时能够恢复到函数被调用前的代码区中继续执行指令。
- 临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。栈帧要为这些变量开辟内存空间。
- 保存的上下文:包括在函数调用前后需要保持不变的寄存器。
- 栈帧状态值:保存前栈帧的顶部和底部的地址,用于在本栈被弹出后恢复出上一个栈帧。
- 注:函数栈帧的大小并不固定,一般与其对应函数的局部变量多少有关。函数运行过程中,其栈帧大小也是在不停变化的。
-
寄存器ebp和esp
- 寄存器esp指向当前栈帧的栈顶,寄存器 ebp指向当前栈帧的帧底。(栈帧的栈顶也是低地址,和栈方向一致) 当前栈帧一定是位于栈的栈顶处。 因此esp其实指的也是调用栈的栈顶。ebp也成为帧指针。
- 调用过程时ebp和esp的变化:(不是我的图,已标转载)
- 寄存器ebp存放的是调用函数(或者叫主调函数)的ebp寄存器的地址,ebp的前一个单元存放的是函数返回的地址。这样就可以根据当前ebp的值回溯出整个任务的调用栈。
- 寄存器esp始终指向栈的顶部。