操作系统会为
进程
(正在运行的应用程序)分配内存空间
用于存放程序在执行过程中需要的代码和数据。根据内存的使用方式不同,会把内存划分成几个具有不同功能的区域。其中一块区域叫做堆栈
(也被称为栈),它和数据结构中的栈一样具有后进先出
的性质。堆栈
用于记录函数在调用过程中产生的信息,比如函数局部变量和参数等信息。本文后面提到的栈
均指的是内存中的堆栈
。
CPU提供了对栈内存进行压栈
(push)和出栈
(pop)的指令,同时还有一个叫做栈指针
(sp)的寄存器用来保存栈顶
位置的内存地址
。栈内存
是从高地址
向低地址
空间发展,这一点跟正常的思维习惯有点不一样,也就是说当你向栈
中push
一个新的数据时,栈的地址会变小。
为了方便表示本文后面的所有栈结构图中的每个格子都是8个字节 ,同时我们也假设push和pop指令每次操作8个字节。
下图是一个大小为80个字节(图中每个格子是8个字节)的栈
,地址范围是0~79。栈指针
指向栈顶的位置:
后面提到的指令均是类似于C语言的伪代码,只是用来描述栈的变化过程。
压栈时把栈指针
往低地址
移动也就是减小栈指针,然后把数据写入到以栈指针
开始的内存中。
例如要把数值123
压入到栈中,对应的指令就是:
push(123);
它的效果等价于下面这两条指令:
sp = sp - 8;
*sp = 123;
由于我们假设push指令每次操作8个字节,所以第1条指令先把sp
(栈指针)向低地址移动8个字。然后第2条指令再把数据写入到以sp
开始的那8个字节的内存中。*sp
表示的是栈指针
所指向的那块内存空间,而不是栈指针
本身。
栈变化过程:
出栈时先取出以栈指针
开头的8个字节(我们假设pop每次操作8个字节)的数据,再把栈指针
向高地址移动8个字节也就是增加栈指针。
把压栈例子中栈顶
的数据出栈至变量rax
中,对应的指令:
pop(rax);
它的效果等价于下面这两条指令:
rax = *sp;
sp = sp + 8;
先把以栈指针
开始的8个字节的数据放入变量rax
中,由于压栈例子中压入的是123,所以此时出栈的数据也是123,最后把栈指针
向高地址移动8个字节。
栈变化过程: