C语言——内存分配
“要想深入学习C语言,不可避免要去弄懂C语言的内存分配,我也是最近才看了关于这一部分的内容,看完后收获很大,很多以前不是很明白的地方也变得清晰起来。”
01
—
虚拟内存
我们要知道,在编程过程中,我们直接操作的内存其实是虚拟内存,使用的地址也是虚地址,但虚拟内存更易于我们来理解程序的执行过程。
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
上面是百度百科对虚拟内存的定义。应该是比较好理解的,不能理解也没关系,不会影响你阅读这篇文章的。下面,我们所提到的内存,均为虚拟内存。
02
—
内存分配
首先,我们来看看内存长啥样。
对,就是这么一个简陋的长条子。我们的程序就是在这么一段内存里产生了各种各样奇妙的结果。
最上面是高位地址,往下是低位地址。我们来一部分一部分地来看。
代码区
顾名思义,你的代码全部储存在这里。程序执行的时候,顺序结构只会执行一次,如果是递归,或者调用函数,则需要栈来实现。这一段区域还存储着一些常量,比如字符串常量。
rodata区域
这一部分在图上没有,但确实很重要的一块,这里存储着常量,但是不是所有常量都存储在这里。
全局初始化数据区/静态数据区(Data Segment)
这一部分存储着静态变量和已经初始化(非零)的全局变量,在这里存储的数据都是已经初始化过的。
未初始化数据区(BSS)
这一部分存储着未初始化的全局变量和初始化为0的全局变量。
堆区
在程序中使用malloc和calloc分配的内存便是从这里分配的。
栈区
这一部分存放函数的参数值、局部变量的值等。它类似于数据结构中的栈。每当一个函数被调用,该函数返回地址和一些关于调用的信息,比如某些寄存器的内容,被存储到栈区。然后这个被调用的函数再为它的自动变量和临时变量在栈区上分配空间,这就是C实现函数递归调用的方法。由于递归会使用大量栈空间,所以递归一定要慎用,否则有栈溢出的可能。
命令行参数区
这里储存着调用文件时命令行传入的参数以及系统的环境变量。
调用一个函数的时候,参数会按照从右向左的顺序压入栈中,当执行完毕时,会从下往上依次返回,所以虽然内存有限,但却能运行很大的程序。