应该指出,栈并不是栈式语言语义的一部分。这类语言的 语义仅要求每激活一个单元,其局部变量应绑定于这个刚 激活单元的活动记录,并遵循作用域的规则。而栈是实现 这种语义的有效模型。 虽然半静态变量和半动态变量都是栈式分配的,但半静态 变量绑定于活动记录的常数位移,即它可在编译时分配于 活动记录中。而半动态变量则在编译时只在活动记录中分 配了它的描述符,需待所有单元U被激活后,在新建立的U 的活动记录顶端(即栈顶按描述符信息,分配半动态变量的 存储空间。 基于栈的存储分配也完全适用于静态语言,栈式分配也被 许多静态语言的实现所采用。 16
16 应该指出,栈并不是栈式语言语义的一部分。这类语言的 语义仅要求每激活一个单元,其局部变量应绑定于这个刚 激活单元的活动记录,并遵循作用域的规则。而栈是实现 这种语义的有效模型。 虽然半静态变量和半动态变量都是栈式分配的,但半静态 变量绑定于活动记录的常数位移,即它可在编译时分配于 活动记录中。而半动态变量则在编译时只在活动记录中分 配了它的描述符,需待所有单元U被激活后,在新建立的U 的活动记录顶端(即栈顶)按描述符信息,分配半动态变量的 存储空间。 基于栈的存储分配也完全适用于静态语言,栈式分配也被 许多静态语言的实现所采用
3.堆分配 由于动态变量表示的数据对象,它的长度、个数都有可能 在执行中改变,即在其生存期中动态改变,就不可能在栈 上为这样的对象作分配。例如在 Pascal中,每个指针只能指 向一种类型的对象。假定P在A中已被说明为类型t的指针, B动态嵌套在A中,B中包含了一个分配语句:New(P) 代码 code 静态数据 static data 栈 stack 堆 neap 图62存储组织
17 3. 堆分配 由于动态变量表示的数据对象,它的长度、个数都有可能 在执行中改变,即在其生存期中动态改变,就不可能在栈 上为这样的对象作分配。例如在Pascal中,每个指针只能指 向一种类型的对象。假定P在A中已被说明为类型t的指针, B动态嵌套在A中,B中包含了一个分配语句:New (P) ... 代码 code 静态数据 static data 栈 stack 堆 heap 图6.2 存储组织
它建立一个类型为的对象,并将对象的地址赋于P。当B执 行到这个分配语句时,B的活动记录在栈顶,而A的活动记 录在B的活动记录下面。这个A中定义的、B中分配的P指向 的对象,不能在B的活动记录中分配。因为B的活动结束时 它的活动记录就得释放,但P所指向的这个对象的生存期并 未结束,不应该释放。可是将这个对象分配在A的活动记录 中也是行不通的。因为如果P所指的这个对象是个灵活数组 这就无疑要重新构造栈了。所以对这样的对象可另辟一个 并非栈模式的存储区进行分配,这个存储区称为堆。一般 而言,出现下列情况 1)单元活动结束后,局部变量的值还需保留。 (2)调用单元与被调用单元的生存期不满足嵌套关系,即出 现交叉现象,那么后进先出的模式是不合适的,必须用堆 模式分配。 因此运行时,常把目标代码与全局变量、静态数据安排在 存储空间的底端。在静态空间之上为栈空间,堆则安排在 存储空间的另一端,栈和堆可动态的迎面增长,如图62所 18
18 它建立一个类型为t的对象,并将对象的地址赋于P。当B执 行到这个分配语句时,B的活动记录在栈顶,而A的活动记 录在B的活动记录下面。这个A中定义的、B中分配的P指向 的对象,不能在B的活动记录中分配。因为B的活动结束时, 它的活动记录就得释放,但P所指向的这个对象的生存期并 未结束,不应该释放。可是将这个对象分配在A的活动记录 中也是行不通的。因为如果P所指的这个对象是个灵活数组, 这就无疑要重新构造栈了。所以对这样的对象可另辟一个 并非栈模式的存储区进行分配,这个存储区称为堆。一般 而言,出现下列情况: (1) 单元活动结束后,局部变量的值还需保留。 (2) 调用单元与被调用单元的生存期不满足嵌套关系,即出 现交叉现象,那么后进先出的模式是不合适的,必须用堆 模式分配。 因此运行时,常把目标代码与全局变量、静态数据安排在 存储空间的底端。在静态空间之上为栈空间,堆则安排在 存储空间的另一端,栈和堆可动态的迎面增长,如图6.2所 示
§6.2静态务配 如前所述,一个语言如果不允许递归调用、动态数组和动态 类型时,便可采用静态分配模式。 FORTRAN是一种典 型的静态语言。下面讨论它的静态分配。 、 FORTRAN程序的运行时结构 个 FORTRAN程序由一组程序单元,即一个主程序,若干 个子程序或者函数组成。每个单元可独立编译,绑定于 个活动记录。活动记录及变量在运行前便可建立,其 生存期延续到整个程序执行结束。变量的作用域局部于 它被说明的那个单元,而 COMMON语句说明的变量是 全局于各单元的全局变量,分配在全局数据活动记录中 对于 FORTRAN来说,本章第一节中提到的动态链和静 态链、动态变量及半动态变量的描述符不会出现在活动 记录中。如果只关心存储分配,则一个 FORTRAN程序 的编译要经过三个步骤
19 §6.2 静态分配 如前所述,一个语言如果不允许递归调用、动态数组和动态 类型时,便可采用静态分配模式。FORTRAN是一种典 型的静态语言。下面讨论它的静态分配。 一、FORTRAN 程序的运行时结构 一个FORTRAN程序由一组程序单元,即一个主程序,若干 个子程序或者函数组成。每个单元可独立编译,绑定于 一个活动记录。活动记录及变量在运行前便可建立,其 生存期延续到整个程序执行结束。变量的作用域局部于 它被说明的那个单元,而COMMON语句说明的变量是 全局于各单元的全局变量,分配在全局数据活动记录中。 对于FORTRAN来说,本章第一节中提到的动态链和静 态链、动态变量及半动态变量的描述符不会出现在活动 记录中。如果只关心存储分配,则一个FORTRAN程序 的编译要经过三个步骤
(1)编译时,变量约束于活动记录的常量位移因此每一个 变量的引用都可用二元式(单元名,位移)表示。而转换控 制语句中对指令的引用也可翻译成二元式(单元名,指令 在代码段中的位移)。 (2)连接时,须将程序所有单元连接起来。每连接一个单元 将它的代码段分配到代码区,活动记录分配到数据区。 这时,翻译后的所有引用活动记录和代码段的二元式都 可转换成一个单一的存储地址。例如单元的活动记录从 1000存储单元开始分配,则二元(i,6)表示的数据单元引 用地址为D[1006。同样,单元的代码段从2000存储单元 开始分配,则(5表示的指令地址为C2005。当然,实 际的连接器应将各单元的代码段连接成一个可重定位 ( Relocatable)代码,只是我们关心连接过程,所以避开了 (3)装入时,将连接后的可重定位代码程序装入主存储器并 定位,成为可直接执行的机器代码,并将i指向程序第 条指令,使程序处于可执行状态 20
20 (1) 编译时,变量约束于活动记录的常量位移,因此每一个 变量的引用都可用二元式(单元名,位移)表示。而转换控 制语句中对指令的引用也可翻译成二元式(单元名,指令 在代码段中的位移)。 (2) 连接时,须将程序所有单元连接起来。每连接一个单元, 将它的代码段分配到代码区,活动记录分配到数据区。 这时,翻译后的所有引用活动记录和代码段的二元式都 可转换成一个单一的存储地址。例如单元i的活动记录从 1000存储单元开始分配,则二元(i, 6)表示的数据单元引 用地址为D[1006]。同样,单元i的代码段从2000存储单元 开始分配,则(i, 5)表示的指令地址为C[2005]。当然,实 际的连接器应将各单元的代码段连接成一个可重定位 (Relocatable)代码,只是我们关心连接过程,所以避开了 它。 (3) 装入时,将连接后的可重定位代码程序装入主存储器并 定位,成为可直接执行的机器代码,并将ip指向程序第 一条指令,使程序处于可执行状态