C语言基础,从虚拟内存到进程,栈都用在了哪些地方(原创)

前面在说到虚拟内存的时候,有朋友提到进程,所以我简单的来说下进程,进程是什么,进程就是正在进行的一个程序,它有着自己完整独立的进程空间,是一个动态概念,是过程,而不是一个静态概念。我们前面提到的软件的地址空间实际上就说的是进程的地址空间,所以说一个进程往往对应着一个地址空间。不过有一点需要注意的是,做过开发的朋友都会了解到,一个软件中是可以存在多个进程的,一个进程又可以存在多个线程。

既然知道了一个程序对应一个进程,那么我们就可以很好理解为什么电脑可以看电影的同时又可以玩游戏做其他事情,因为每个程序都会有一个进程,这些进程互不干扰,各自运行。(理论上不干扰,但是在手机中,如果运行的软件内存不够,会将不用的一些软件强制关掉。)

通过上面的一些了解,我们可以看出,每一个程序在运行的时候,系统都会分配一个完整的虚拟内存空间,但是在使用过程中,我们经常会说堆和栈之类的,很多人可能会误解,堆和栈是和程序的内存空间完全独立的,这种说法实际上是错误的。既然一个进程会被分配一个完整的虚拟内存空间,那么其完整性就代表着,系统会在这个容器中分配多个区域,并将其分别用做堆和栈中,我们在前面的文章中讲过内存分配问题,不过都是浅谈,所以今天就较为深入的了解下栈的概念和使用。

在前面的学习中说过,栈的分配和释放都是有系统自动分配和释放的,当时没说函数,所以只说了用来储存一些局部变量,基本数据类型等,实际上,这只是冰山一角,栈的最大用处就是储存函数的参数,帮助函数完成调用。这样说的原因是因为我们定义的参数都是有作用域的,而在函数范围内定义的这些参数,它们只在这个函数内有用,当某个函数被调用的时候,定义的参数和变量等都会被分配内存,帮助函数完成调用,而这些参数的储存位置就是在栈中,当函数调用完毕后,系统就会将这些分配好的内存销毁掉,这也就是为什么我们的参数和变量只能在函数中有效的原因。

对于函数的调用来说,栈是分不开的,所以我们简单说函数在栈上的调用方式。首先,函数在调用的时候,会将我们定义的函数中,所有需要的参数和信息等全部放进去,也就是进栈,而它的过程我们可以视为当前函数内容的活动记录,这个活动记录是先从上一个函数调用中知道这个函数是先从哪里开始,然后实参,返回地址,寄存器等先进栈,然后给变量和返回值等分配空间,最后再将其他寄存器进栈。(寄存器简单的说就是大小有限制,但是存取速度很快的部件,是CPU的组成部分),这就是函数的调用过程,说的不是很细,但我个人理解就是这个意思。函数的调用时候的出栈方式,实际上是遵循先进后出的特点,我们将上面的过程反向理解,最后根据返回地址寻找下一个指令,并且出栈即可。

我们知道内存中,有高位和低位之说,而栈就位于高位中。栈有一个特性就是先进后出,我觉得这种特性完全可以看做水桶,往里添水时,是不是水先到桶底,然后慢慢向上涨起来的,在往出盛水时,是从上面往出盛水呢。是不是典型的先进后出案例,不过栈长的不只是水,而是将水和桶沿一起向上加的,这个过程在栈里被称为入栈和出栈。

我们知道内存中,有高位和低位之说,而栈就位于高位中。栈有一个特性就是先进后出,我觉得这种特性完全可以看做水桶,往里添水时,是不是水先到桶底,然后慢慢向上涨起来的,在往出盛水时,是从上面往出盛水呢。是不是典型的先进后出案例,不过栈长的不只是水,而是将水和桶沿一起向上加的,这个过程在栈里被称为入栈和出栈。

栈和水桶

从图中可以看到的是进栈的操作是将栈顶上移了,但是在虚拟地址中,我们的栈顶和栈底可不是上面这种方式是向上的,栈底始终在高地址,而栈顶却是向下的低地址。入栈时,栈顶持续下移,出栈时,栈顶上移。是不是非常有趣。

地址

栈是一片连续的空间,但是对于进程空间来说,它的大小是有限的,这个限制是在软件编译阶段,系统就自动分配好的,如果我们我们使用栈的时候,里面的内容超过了这个限制,那么就会出现我们所说的栈溢出。(由于没有说线程,我们暂时认为栈的最大值是对于进程来说的)当然,这些是可以通过系统设置进行更改的,有兴趣的朋友可以去百度一下(Google比较全)。

相关推荐
新闻聚焦
猜你喜欢
热门推荐
返回列表