系统为进程分配数据空间有三种形式。
静态分配
整块静态分配空间,包括其中的所有数据实体,都是在进程创建时由系统一次性分配的(同时为UNIX称为Text的代码分配空间)。这块空间在进程运行期间保持不变。
初始化的和未初始化的实体分别放在初始化数据段和未初始化数据段(BSS)。后者和前者不同,在.o文件a.out文件里都不存在(只有构架信息),在进程的虚拟空间里才展开。
extern变量和static变量采用静态分配。
在进程创建时做静态分配,分配正文(text)段、数据段和栈空间。
正文和初始化数据是按a.out照样复制过来;未初始化数据按构架信息展开,填以0或空;栈空间的大小由链接器开关(具体哪个开关忘了)决定。
栈分配
整个栈空间已在进程创建时分配好。栈指针SP的初值的设定,确定了栈空间的大小。链接器的某个开关可以设定栈空间的大小。在进程运行期间,栈空间的大小不变。但是,在进程刚启动时,栈空间是空的,里面没有实体。在进程运行期间,对具体实体的栈分配是进程自行生成(压栈)和释放(弹出)实体,系统并不参与。
auto变量和函数参数采用栈分配。
只要压入的实体的总长度不超过栈空间尺寸,栈分配就与系统无关。如果超过了,就会引发栈溢出错误。
堆分配
当进程需要生成实体时,向系统申请分配空间;不再需要该实体时,可以向系统申请回收这块空间。
堆分配使用特定的函数(如malloc()等)或操作符(new)。所生成的实体都是匿名的,只能通过指针去访问。
对实体来说,栈分配和堆分配都是动态分配:实体都是在进程运行中生成和消失。而静态分配的所有实体都是在进程创建时全部分配好的,在运行中一直存在。
同为动态分配,栈分配与堆分配是很不相同的。前者是在进程创建时由系统分配整块栈空间,以后实体通过压栈的方式产生,并通过弹出的方式取消。不管是否产生实体,产生多少实体,栈空间总是保持原来的大小。后者并没有预设的空间,当需要产生实体时,才向系统申请正好能容纳这个实体的空间。当不再需要该实体时,可以向系统申请回收这块空间。因此,堆分配是真正的动态分配。
显然,堆分配的空间利用率最高。
栈分配和静态分配也有共性:整块空间是在进程创建时由系统分配的。但是,后者同时分配了所有实体的空间,而前者在进程启动时是空的。另外,栈上的实体和数据段里的实体都是有名实体,可以通过标识符来访问。
静态分配
栈分配
堆分配
整块空间生成
进程创建时
进程创建时
用一点分配一点
实体生成时间
进程创建时
进程运行时
进程运行时
实体生成者
操作系统
进程
进程申请/系统实施
生命期
永久
临时
完全可控
有名/匿名
有名
有名
匿名
访问方式
能以标识访问
能以标识访问
只能通过指针访问
空间可否回收
不可
不可
可以