1) 栈由操作系统分配,用于存放函数的参数值,局部变量等等。
2)内存地址生长方向自上向下 比如
int main() {
int a; //栈
int b; //栈
int c; //栈
}
这里b的地址小于变量a的地址,即后定义的变量地址低于先定义的变量。
3)栈中存储数据的生命周期随着函数的执行完成而结束。
1)堆由开发人员分配和释放。
2)分配方式类似链表。
3)堆的内存地址由低到高。
4)若先前内存被释放,后面的内存则会利用先前的内存,所以后申请的内存空间并不一定在先申请内存空间的后面。
5)如果堆中的数据没有释放,其生命周期等同于程序的生命周期。
1)管理方式不同。
栈由操作系统自动分配,堆需要我们主动释放,要不然容易产生内存泄露问题。
2)空间大小不同。
栈的大小远远小于堆大小。
3)生长方向不同。
栈生长方向向下,内存地址由高到低。
堆生长方向向上,内存地址由低到高。
4)分配方式不同。
堆:动态分配。
栈:既有静态分配(由操作系统分配)也有动态分配(alloca()函数分配,栈的动态分配的内存由操作系统自动释放)
5)分配效率不同
硬件层级会对栈提供支持:分配专门的寄存器来存放栈的地址,压栈出栈都有专门的指令执行,决定了栈的效率比堆高。
堆是由库函数或者运算符来向内存申请的内存空间。效率比栈低。
6)存放内容不同。
堆:一般堆顶使用一个空字节来存放堆的大小,而堆中的内容由程序员自己决定。
栈:函数返回地址,相关参数,局部变量,寄存器内容等。
1)参数传递
调用者将函数参数压入栈中或者通过寄存器传递。
2保存上下文
保存当前函数的执行状态,例如保存寄存器中的值。以便在函数返回后能够恢复到调用前的状态。
3)跳转至被调用函数
将控制权转移至被调用函数的起始位置,被调用函数执行前,需要为其分配内存空间来存储局部变量和临时数据。
4)局部变量和临时数据
局部变量和临时数据存储在栈上。(静态变量不是栈而是存放在数据段或者是BSS段)。
6)返回地址
将返回值存放在指定的寄存器或内存位置。函数执行完毕后,会通过返回地址找到调用该函数的指令,从而返回到调用者的位置。
7)恢复上下文
调用者会从栈中恢复之前保存的上下文信息,调用者就能够继续执行,同时也可以获得被调用函数的返回值。
出栈过程:执行恢复上下文,将栈顶指针指向原来位置。