编译原理_chapter9
合集下载
编译原理chapter9 运行时存储空间组织

编译原理
chapter9
运行时存储空间组织
Chapter9 运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
9.1 目标程序运行时的活动 9.2 运行时存储器的划分 9.3 简单的栈式存储分配 9.4 嵌套过程语言的栈式实现 9.5 堆式动态存储分配
编译原理
chapter9
运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
1. 带有静态链的活动记录 带有静态链 静态链的活动记录 静态链:它指向直接外层过程的活动记录的起始位置, 静态链:它指向直接外层过程的活动记录的起始位置, 直接外层过程的活动记录的起始位置 用于访问各外层的变量(非局部变量)。 用于访问各外层的变量(非局部变量)。
动态链:指向调用本过程的最新活动 ④. 动态链:指向调用本过程的最新活动 返回地址 记录的起始地址; 记录的起始地址; 动态链 每个活动记录的大小在编译时可以确定 SP ( 除动态数据 ),因此以 为变址器可方便的访问各个数据 ,因此以SP为变址器可方便的访问各个数据
编译原理
chapter9
运行时存储空间组织
top
u=15 v=10 形式单元 参数个数 gcd(15,10)
sp top sp
2 返回地址 老sp
x=15 y=10
main() 全局 /静态区 静态区
编译原理
chapter9
运行时存储空间组织
program p; 9.4 嵌套过程语言的栈式实现 var a,x:integer; 语言为例, 以Pascal语言为例Q(b:integer); 语言为例 由于允许嵌套定义过程, procedure ,由于允许嵌套定义过程,则会 var i:integer; 出现“非局部名字的访问”问题。 出现“非局部名字的访问”问题。因此简单的栈式存储分 procedure R(u:integer;var v:integer); 配不适用。 配不适用。 var c,d:integer; begin if u=1 then R(u+1,v) 活动记录中可配有静态链和嵌套层次表两种方式来实现。 静态链和嵌套层次表43;c)*(b-d); 两种方式来实现。 end {R} begin …. R(1,x); ……. end {Q} procedure S; var c,i:integer; begin a=1;Q(c); …….end {S} begin a=0;S;…… end
chapter9
运行时存储空间组织
Chapter9 运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
9.1 目标程序运行时的活动 9.2 运行时存储器的划分 9.3 简单的栈式存储分配 9.4 嵌套过程语言的栈式实现 9.5 堆式动态存储分配
编译原理
chapter9
运行时存储空间组织
编译原理
chapter9
运行时存储空间组织
1. 带有静态链的活动记录 带有静态链 静态链的活动记录 静态链:它指向直接外层过程的活动记录的起始位置, 静态链:它指向直接外层过程的活动记录的起始位置, 直接外层过程的活动记录的起始位置 用于访问各外层的变量(非局部变量)。 用于访问各外层的变量(非局部变量)。
动态链:指向调用本过程的最新活动 ④. 动态链:指向调用本过程的最新活动 返回地址 记录的起始地址; 记录的起始地址; 动态链 每个活动记录的大小在编译时可以确定 SP ( 除动态数据 ),因此以 为变址器可方便的访问各个数据 ,因此以SP为变址器可方便的访问各个数据
编译原理
chapter9
运行时存储空间组织
top
u=15 v=10 形式单元 参数个数 gcd(15,10)
sp top sp
2 返回地址 老sp
x=15 y=10
main() 全局 /静态区 静态区
编译原理
chapter9
运行时存储空间组织
program p; 9.4 嵌套过程语言的栈式实现 var a,x:integer; 语言为例, 以Pascal语言为例Q(b:integer); 语言为例 由于允许嵌套定义过程, procedure ,由于允许嵌套定义过程,则会 var i:integer; 出现“非局部名字的访问”问题。 出现“非局部名字的访问”问题。因此简单的栈式存储分 procedure R(u:integer;var v:integer); 配不适用。 配不适用。 var c,d:integer; begin if u=1 then R(u+1,v) 活动记录中可配有静态链和嵌套层次表两种方式来实现。 静态链和嵌套层次表43;c)*(b-d); 两种方式来实现。 end {R} begin …. R(1,x); ……. end {Q} procedure S; var c,i:integer; begin a=1;Q(c); …….end {S} begin a=0;S;…… end
编译原理 课件第九章

上下文语义的合法性检查的依据
在语义分析中,符号表所登记的内容将用于语义检查(如检查 一个名字的使用和原先的说明是否一致)和产生中间代码。通 过符号表中属性记录可进行相应上下文的语义检查。 例如,在一个C语言程序中出现 … int i [3][5]; //定义整型数组i … float i[4][2]; //定义实型数组i,重定义冲突 … int i [3][5]; //定义整型数组i,重定义冲突 … 编译过程首先在符号表中记录了标识符i的属性是3×5个整型元 素的数组,而后在分析第二、第三这两个定义说明时编译系统 可通过符号表检查出标识符i的二次重定义冲突错误。本例还可 以看到不论在后二句中i的其它属性与前一句是否完全相同,只 要标识符名重定义,就将产生重定义冲突的语义错误。
9.1符号表的作用和地位 符号表的作用和地位 9.2符号的主要属性及作用 符号的主要属性及作用 9.3符号表的组织 符号表的组织
9.1 符号表的作用和地位
收集符号属性 上下文语义的合法性检查的依据 作为目标代码生成阶段地址分配的依据
收集符号属性
编译程序扫描说明部分,收集有关标识符的属性,并在符号表 中建立符号的相应属性信息。 例如,编译程序分析到下述两个说明语句 int A; float B[5]; 则在符号表中收集到关于符号A的属性是一个整型变量,关于 符号B的属性是具有5个浮点型元素的一维数组。
9.2 符号的主要属性及作用
符号属性
1 符号名 2 符号的类型 3 符号的存储类别 4 符号的作用域及可视性 5 符号变量的存储分配信息 6 符型的成员信息 (3) 函数及过程的形参
① 符号名 符号表中设置一个符号名域,存放该标识符,该域通 常就是符号表的关键字域。
作为目标代码生成阶段地址分配的依据
编译原理chapter9优化

goto B2
t11 := 4 * i x := a[t11] t12 := 4 * i t13 := 4 * n t14 := a[t13] a[t12] := t14 t15 := 4 * n a[t15] := x
10.2.2 公共子表达式删除
如果表达式E先前已计算,并且从先前的计算到E的再次出现,E中变量的 值没有改变,那么E的这个再次出现称为公共子表达式
(2) j := n
do i = i +1; while(a[i]<v); (3) t1 := 4 * n
do j =j 1;while (a[j]>v); (4) v := a[t1]
if (i >= j) break;
(5) i := i + 1
x=a[i]; a[i]=a[j]; a[j]=x; (6) t2 := 4 * i
}
(7) t3 := a[t2]
10.2 优化的主要种类
本节所用的例子
i = m 1; j = n; v = a[n]; (9) j := j 1
while (1) {
(10) t4 := 4 * j
do i = i +1; while(a[i]<v); (11) t5 := a[t4]
do j =j 1;while (a[j]>v); (12) if t5>v goto (9)
10.2.2 公共子表达式删除
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * i x := a[t6] t7 := 4 * i t8 := 4 * j t9 := a[t8] a[t7] := t9 t10 := 4 * j a[t10] := x
t11 := 4 * i x := a[t11] t12 := 4 * i t13 := 4 * n t14 := a[t13] a[t12] := t14 t15 := 4 * n a[t15] := x
10.2.2 公共子表达式删除
如果表达式E先前已计算,并且从先前的计算到E的再次出现,E中变量的 值没有改变,那么E的这个再次出现称为公共子表达式
(2) j := n
do i = i +1; while(a[i]<v); (3) t1 := 4 * n
do j =j 1;while (a[j]>v); (4) v := a[t1]
if (i >= j) break;
(5) i := i + 1
x=a[i]; a[i]=a[j]; a[j]=x; (6) t2 := 4 * i
}
(7) t3 := a[t2]
10.2 优化的主要种类
本节所用的例子
i = m 1; j = n; v = a[n]; (9) j := j 1
while (1) {
(10) t4 := 4 * j
do i = i +1; while(a[i]<v); (11) t5 := a[t4]
do j =j 1;while (a[j]>v); (12) if t5>v goto (9)
10.2.2 公共子表达式删除
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * i x := a[t6] t7 := 4 * i t8 := 4 * j t9 := a[t8] a[t7] := t9 t10 := 4 * j a[t10] := x
编译原理第九章

间的分配中也必须对这些临时变量分配存储空间。
分配策略:如果两个临时变量名作用域不相交,则它们可以分配在
同一单元中。一个临时变量名自它第一次被定值(赋值)的地方起
直至它最后一次被引用的地方止,这区间的程序所能到达的全体四
元式构成了它的作用域。 令临时变量名都分配在局部数据区中,若某一单元已分配给某些
临时变量名,则把这些名字的作用域(它们必须互不相交信息记录 )作为此单元的分配信息记录下来。每当要对一个新临时变量名进 行分配时,首先求出此名的作用域,然后按序检查每个已分配单 元,一旦发现新求出的作用域与某个单元所记录的全部作用域均不 相交时就把这个单元分配给这个新名,同时把它的作用域也添加到 该单元的分配信息之中。如果新临时变量的作用域和所有已分配单 元的作用域均有冲突,则就分配给它一个新的单元,同时把新名的 作用域作为此单元的分配信息。
适于静态管理的语言必须满足的条件:
1. 数组的上下界必须是常数
2. 过程调用不允许递归
3. 不允许用户动态地建立数据实体
编译程序可以确定出现在程序中的数据实体的地址(一般相 对于各数据区基地址的偏移量)。由于过程调用不允许递归,数 据实体的存储地址就和过程相联系,过程调用的活动记录就可 以直接安排在目标代码之后,并把各数据项的存储地址填入到 相关的目标代码中,以便在运行时访问这些数据存储空间。这 里,不存在对存储区域的再利用。目标代码运行时不必进行运 行时的存储管理。
上一页
下一页
18
3.2 FORTRAN的局部数据区
FORTRAN的编译程序将每个程序段都定义对应的局部数据区,每个数据区都 有一个编号,在地址分配时,在符号表中,对每个数据名将登记上它是属于哪个 数据区的,以及在该区中的相对位置(DA、ADDR)。
分配策略:如果两个临时变量名作用域不相交,则它们可以分配在
同一单元中。一个临时变量名自它第一次被定值(赋值)的地方起
直至它最后一次被引用的地方止,这区间的程序所能到达的全体四
元式构成了它的作用域。 令临时变量名都分配在局部数据区中,若某一单元已分配给某些
临时变量名,则把这些名字的作用域(它们必须互不相交信息记录 )作为此单元的分配信息记录下来。每当要对一个新临时变量名进 行分配时,首先求出此名的作用域,然后按序检查每个已分配单 元,一旦发现新求出的作用域与某个单元所记录的全部作用域均不 相交时就把这个单元分配给这个新名,同时把它的作用域也添加到 该单元的分配信息之中。如果新临时变量的作用域和所有已分配单 元的作用域均有冲突,则就分配给它一个新的单元,同时把新名的 作用域作为此单元的分配信息。
适于静态管理的语言必须满足的条件:
1. 数组的上下界必须是常数
2. 过程调用不允许递归
3. 不允许用户动态地建立数据实体
编译程序可以确定出现在程序中的数据实体的地址(一般相 对于各数据区基地址的偏移量)。由于过程调用不允许递归,数 据实体的存储地址就和过程相联系,过程调用的活动记录就可 以直接安排在目标代码之后,并把各数据项的存储地址填入到 相关的目标代码中,以便在运行时访问这些数据存储空间。这 里,不存在对存储区域的再利用。目标代码运行时不必进行运 行时的存储管理。
上一页
下一页
18
3.2 FORTRAN的局部数据区
FORTRAN的编译程序将每个程序段都定义对应的局部数据区,每个数据区都 有一个编号,在地址分配时,在符号表中,对每个数据名将登记上它是属于哪个 数据区的,以及在该区中的相对位置(DA、ADDR)。
编译原理课件Chapter9

的偏移量,放在table表中的adr域,生成目标代 码时再放在code中的a域
procedure enter(k:object ); begin (* enter object into table *) tx:=tx+1; with table[tx] do (* 开域语句 *) begin kind:=k; (*表示table[tx].kind:=k;*) name:=id;(*表示table[tx].name:=id;*)
9.4.1 分表结构的组织管理
基本思想:每当编译程序扫描到一个分 程序结构开始时,为该分程序建立一张符 号表,在该分程序中定义的标识符,都被 登录在该符号表中。 而当编译程序扫描到一个分程序的结束 时,编译程序释放为该分程序所建立的符 号表。 这种符号表的分表结构与源程序的分程 序层次结构一一对应
9.3.3 关键字域的组织
符号表的关键字域(段)就是符号名称 第一种:等长关键字域(段)符号表 第二种:不等长关键字段符号表—采用关 键字池的索引结构。(P216)
其它域的组织
对于数组:维数、上下界值、计算下标量地址 所用的信息以及数组元素类型等 对于记录(结构、联合):域的个数、每个域名、 地址位移、类型等 对于过程或函数:形参个数、所在层次、函数返 回值类型、局部变量所占空间大小等
四元式表QT
9.3.2 符号表项的排列
符号表作为一个多元组,表中元组的排列组 织是构造符号表的重要成分。在编译程序的整 个工作过程中,符号表被频繁地用来建立表项, 找查表项,填充和引用表项的属性。因此表项 的排列组织对该系统运行的效率起着十分重要 的作用。在编译程序中,符号表项的组织传统 上采用三种构造方法。即线性法,排序组织法 及散列法。
编译原理 9章

address(A[i , j])=address(A[1,1])+(i-1)*n+(j-1)
address(A[i , j])=address(A[1,1])-n-1+(i*n+j)
注:上式中的第一部分是一常数,仅需计算一次。
2008年3月
设A是下面的说明语句定义的一个n维数组: array A[l1..u1 , l2..u2 , .. , ln..un] of integer
2008年3月
•多块存储方式 多块存储方式是对每一行都分配一个单 块数据区,每行的元素按递增次序存放在这块 数据区中。此外,还设一个指示器表,用以指 示这些单块数据区的开始位置。
2008年3月
9.3.3 多块存储方式
B0 指向第 1 行的指示器 指向第 2 行的指示器 … 指向第 m 行的指示器 A[2, 2] Rm : A[m, 1] A[m, 2] … A[m, n] … A[2, n] … A[1, n] R2 : R1 : A[2, 1] A[1, 1] A[1, 2]
•数据区
数据区是指一片相连的存储单元。 例:PASCAL主程序中所说明的变量运行时所需要 的存储单元以及主程序运行时所需要的临时工作 单元一起构成了一个数据区。
2008年3月
在编译时,任何变量运行时存储单元都可由一 对偶(数据区编号,位移)表示。其中,数据区编号 是分配给数据区的唯一编号;位移是指该存储单元相 对于该数据区起址的距离(或单元数)。 例如:对于编号为10的数据区 它的第1个存储单元可表示为(10,0) 第2个存储单元可表示为(10,1)
2008年3月
数组分配程序: begin i:=1 ; Size:=1 ; Conspart:=0; while i ≤n do
08979编译原理第九章

– –
–
–
中间表示:四元式 DAG图 控制流图 数据流方程
问题复杂度:往往是NP 完全或NP难
–
简化,小规模问题
…
优化算法
–
代码优化的基本过程
代码的描述 数据流分析(data-flow analysis) 控制流分析(control-flow analysis) 变换 (transformations)
(3)T1:=4*I (5)T3:=T2[T1] (6)T4:=T1 (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (12)if I<=20 goto(3)
(3‘)T1:=T1+4
(12)if I<=20 goto(5)
(1)P:=0 (2)I:=1 (4)T2:=addr(A)-4 (7)T5:=addr(B)-4 (3)T1:=4*I
性能指标
–
–
–
目标
代码优化
优化策略:
– – –
权衡(trade off):意图、结果 简洁:KISS(Keep It Simple,Stupid) 分工:编译阶段、软件处理、硬件机制
优化的阶段:
front end (I.R)
中间代码优化
(source code)
用户
code generator
基本优化技术
常数合并(合并已知量) 常数传播 代数化简 强度削弱(削弱运算强度) 复写传播 删除多余运算 循环不变代பைடு நூலகம்外提 变换循环控制条件 删除无用赋值
–
–
中间表示:四元式 DAG图 控制流图 数据流方程
问题复杂度:往往是NP 完全或NP难
–
简化,小规模问题
…
优化算法
–
代码优化的基本过程
代码的描述 数据流分析(data-flow analysis) 控制流分析(control-flow analysis) 变换 (transformations)
(3)T1:=4*I (5)T3:=T2[T1] (6)T4:=T1 (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (12)if I<=20 goto(3)
(3‘)T1:=T1+4
(12)if I<=20 goto(5)
(1)P:=0 (2)I:=1 (4)T2:=addr(A)-4 (7)T5:=addr(B)-4 (3)T1:=4*I
性能指标
–
–
–
目标
代码优化
优化策略:
– – –
权衡(trade off):意图、结果 简洁:KISS(Keep It Simple,Stupid) 分工:编译阶段、软件处理、硬件机制
优化的阶段:
front end (I.R)
中间代码优化
(source code)
用户
code generator
基本优化技术
常数合并(合并已知量) 常数传播 代数化简 强度削弱(削弱运算强度) 复写传播 删除多余运算 循环不变代பைடு நூலகம்外提 变换循环控制条件 删除无用赋值
编译原理课件chap9

第九章运行时存储空间组织
编译程序在完成词法、语法和语义分析后, 编译程序在完成词法、语法和语义分析后,在生成目标代 码之前, 码之前,需要把程序的静态正文和实现这个程序的运行时的 活动联系起来弄清楚将来在代码运行时刻, 活动联系起来弄清楚将来在代码运行时刻,源代码中的各种 变量、常量等用户定义的量是如何存放的,如何去访问它们。 变量、常量等用户定义的量是如何存放的,如何去访问它们。 在程序的执行过程中, 在程序的执行过程中,程序中数据的存取是通过与之对 应的存储单元来进行的。在程序语言中, 应的存储单元来进行的。在程序语言中,程序使用的存储单 元都是由标识符来表示的。它们对应的内存地址都是由编译 元都是由标识符来表示的。 程序在编译时或由其生成的目标程序运行时进行分配。 程序在编译时或由其生成的目标程序运行时进行分配。所以 对于编译程序来说存储组织与管理是一个复杂而又十分重要 的问题。 的问题。这一章就是对目标程序运行时的活动和运行环境进 行讨论,主要讨论存储组织与管理, 行讨论,主要讨论存储组织与管理 包括活动纪录的建立与管 理、存储器的组织与存储分配的策略、非局部名称的访问等 存储器的组织与存储分配的策略、 问题。 问题。
第九章 运行时存储空间组织
9。2。3存储分配策略 。 。 存储分配策略 不同的编译程序关于数据空间的存储分配策略可能 不同。静态分配策略在编译是对所有对象分配固定的 不同。静态分配策略在编译是对所有对象分配固定的 存储单元。且在运行是保持不变。 存储单元。且在运行是保持不变。栈式动态分配策略 在运行时把存储器作为一个栈进行管理,运行时, 在运行时把存储器作为一个栈进行管理,运行时,每 当调用一个过程, 当调用一个过程,它所需要的存储空间就动态的分配 于栈顶,一旦退出,它所占空间就予以释放。堆式动 于栈顶,一旦退出,它所占空间就予以释放。 态存储策略在运行时把存储器组织成堆结构, 态存储策略在运行时把存储器组织成堆结构,以便用 在运行时把存储器组织成堆结构 户关于存储空间的申请与归还(回收),凡申请者分 户关于存储空间的申请与归还(回收),凡申请者分 ), 给一块,凡释放者退回给堆。 给一块,凡释放者退回给堆。
编译程序在完成词法、语法和语义分析后, 编译程序在完成词法、语法和语义分析后,在生成目标代 码之前, 码之前,需要把程序的静态正文和实现这个程序的运行时的 活动联系起来弄清楚将来在代码运行时刻, 活动联系起来弄清楚将来在代码运行时刻,源代码中的各种 变量、常量等用户定义的量是如何存放的,如何去访问它们。 变量、常量等用户定义的量是如何存放的,如何去访问它们。 在程序的执行过程中, 在程序的执行过程中,程序中数据的存取是通过与之对 应的存储单元来进行的。在程序语言中, 应的存储单元来进行的。在程序语言中,程序使用的存储单 元都是由标识符来表示的。它们对应的内存地址都是由编译 元都是由标识符来表示的。 程序在编译时或由其生成的目标程序运行时进行分配。 程序在编译时或由其生成的目标程序运行时进行分配。所以 对于编译程序来说存储组织与管理是一个复杂而又十分重要 的问题。 的问题。这一章就是对目标程序运行时的活动和运行环境进 行讨论,主要讨论存储组织与管理, 行讨论,主要讨论存储组织与管理 包括活动纪录的建立与管 理、存储器的组织与存储分配的策略、非局部名称的访问等 存储器的组织与存储分配的策略、 问题。 问题。
第九章 运行时存储空间组织
9。2。3存储分配策略 。 。 存储分配策略 不同的编译程序关于数据空间的存储分配策略可能 不同。静态分配策略在编译是对所有对象分配固定的 不同。静态分配策略在编译是对所有对象分配固定的 存储单元。且在运行是保持不变。 存储单元。且在运行是保持不变。栈式动态分配策略 在运行时把存储器作为一个栈进行管理,运行时, 在运行时把存储器作为一个栈进行管理,运行时,每 当调用一个过程, 当调用一个过程,它所需要的存储空间就动态的分配 于栈顶,一旦退出,它所占空间就予以释放。堆式动 于栈顶,一旦退出,它所占空间就予以释放。 态存储策略在运行时把存储器组织成堆结构, 态存储策略在运行时把存储器组织成堆结构,以便用 在运行时把存储器组织成堆结构 户关于存储空间的申请与归还(回收),凡申请者分 户关于存储空间的申请与归还(回收),凡申请者分 ), 给一块,凡释放者退回给堆。 给一块,凡释放者退回给堆。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
24
2015-4-21
某分段式程序运行时的内存划分
指令代码 常数 程序段1 程序段2 …… 程序段i …… 程序段n 公用数据 临时变量 数组 简单变量 形式单元 寄存器保护区 返回地址 程序段i的活动记录
25
局 部 数 据 区
2015-4-21
静态存储分配策略
顺序分配算法(基于调用图)
按照程序段出现的先后顺序逐段分配 1/22 2/15 3/18
2015-4-21 21
9.2.3 局部数据的组织
在 X86/Linux 机器的结果和 SPARC/Solaris 工作 站不一样,是20和16。 typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 12 double f;8 }a; }b;
9.3 静态存储分配策略
(1)PROGRAM CNSUME (2) CHARACTER *50 BUF (3) INTEGER NEXT (4〕 CHARACTER C,PRDUCE (5) DATA NEXT/1/,BUF/ ' '/ (6) C=PRDUCE()。 (7) BUF(NEXT:NEXT)=C (8〕 NEXT=NEXT+1 (9) IF(C.NE.' ' )GOTO 6 (10) WRITE(*,'(A)')BUF (11) END
10
2015-4-21
9.1.4 参数传递方式
信息交换方式 传统程序设计语言过程间交换信息的方法通 常是通过非局部名字和被调用过程的参数来 实现的。
传值 传地址 传值结果 传名
其主要区别在于实参所代表的究竟是左值、右 值还是实参的正文本身 2015-4-21 11
编译程序组织存储空间时必须考虑的问 题
2015-4-21 22
9.2.4 全局存储分配策略
静态存储分配策略(FORTRAN)
如果在编译时能确定数据空间的大小,则可采用 静态分配方法:在编译时刻为每个数据项目确定 出在运行时刻的存储空间中的位置。
动态存储分配策略(PASCAL,C)
如果在编译时不能确定运行时数据空间的大小, 则必须采用动态分配方法。允许递归过程及动态 申请、释放内存。 栈式动态存储分配 堆式动态存储分配
程序段
6 7/80 5
区域
0~9 0~22
4
3
0~16
23~40 17~31 41~62
27
4/17
6/10
5/23
2 1
思考:如何设计分配算法?
2015-4-21
共需要63个存储单元
9.3 静态存储分配策略
静态分配给语言带来的限制 不允许递归过程 数据对象的长度和它在内存中位置的限制, 必须是在编译时可以知道的 数据结构不能动态建立 例:一个Fortran 77程序
环境把名字映射到左值,而状态把左值映射到右值 赋值改变状态,但不改变环境。
如果环境将名字x映射到存储单元s,我们就说x 被绑定到s
环境 状态
名字
2015-4-21
内存位置 (变量)
值
5
9.1.2 声明的作用域
声明的作用域 是指程序中的这样一段区域,在该区域中,x 的引用均指向x的这一声明。 静态作用域和动态作用域 对于某种程序设计语言,如果只通过考察其程 序就可以确定某个声明的作用域,则称该语 言使用静态作用域; 否则称该语言使用动态作用域
过程能否递归? 当控制从过程的活动返回时,局部变量的值是否要 保留? 过程能否访问非局部变量? 过程调用的参数传递方式? 过程能否作为参数被传递? 过程能否作为结果值传递? 存储块能否在程序控制下动态地分配? 存储块是否必须显式地释放? 这些问题都对存贮分配策略有着直接的影响!
第9章 运行时的存储组织
9.1 与存储组织有关的源语言概念与特征 9.2 存储组织 9.3 静态存储分配 9.4 栈式存储分配 9.5 栈中非局部数据的访问 9.6 堆管理 9.7 本章小结
2015-4-21 2
9.1 与存储组织有关的源语言概念与特征
编译程序必须准确地实现包含在源程序中的 各种抽象概念 各种抽象概念,如名字、作用域、数据类型、 操作符、过程、参数和控制流结构等,
采用栈式存储分配机制 活动记录:运行时,每当进入一个过程就有一个 相应的活动记录压入栈顶。 活动记录一般含有连接数据、形式单元、局部变 量、局部数组的内情向量和临时工作单元等。
15
2015-4-21
每个过程的活动记录内容
——非嵌套语言(如C)
TOP 临时变量 数组内情向量 简单变量 形式单元
2015-4-21 20
9.2.3 局部数据的组织
在 SPARC/Solaris工作站上下面两个结构的 size 分别是24和16,为什么不一样? typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 16 double f;8 }a; }b;
9.3 静态存储分配策略
(12)CHARACTER FUNCTION PRDUCE() (13) CHARACTER * 80 BUFFER (14) INTEGER NEXT (15) SAVE BUFFER,NEXT (16) DATA NEXT/81/ (17) IF(NEXT.GT.80)THEN (18) READ(*,'(A)')BUFFER (19) NEXT=1 (20) END IF (21) PRDUCE=BUFFER(NEXT:NEXT) (22 ) NEXT=NEXT+1 (23 ) END
6
2015-4-21
9.1.2 声明的作用域
作用域的显式控制 C++、Java和C#等使用public、private和 protected这样的关键字,对作用域进行显式控 制。 声明的作用域是通过符号表进行管理的
2015-4-21
7
9.1.3 过程及其活动
将“过程、函数和方法”统称为“过程” 过程定义是一个声明,它的最简单形式是把 一个标识符和一个语句联系起来。 该标识符是过程名,而这个语句是过程体。
2015-4-21
23
9.3 静态存储分配策略
如果在编译时就能确定一个程序在运行时所需 要的存储空间的大小,则在编译时就能安排好 目标程序运行时的全部数据空间,并能确定每 个数据项的地址,存储空间的这种分配方法称 为静态存储分配。必须满足如下条件:
数据对象的长度和它在内存中的位置在编译时必须 是已知的; 不允许过程的递归调用,因为一个过程的所有活动 都是用同样的局部名字绑定的; 数据结构不能动态建立,因为没有运行时的存储分 配机制。
2 1
SP 0
2015-4-21
参数个数 返回地址 旧SP
对任何局部变量X的引 用可表示为变址访问: dx[SP] dx:变量X相对于活动记 录起点的地址,在编译 时可确定。
16
每个过程的活动记录内容
——嵌套语言(如Pascal)
TOP 临时变量 数组内情向量
连接数据
局部变量
形式单元 2 1 SP0
9.3 静态存储分配策略
C 语言程序的全局变量和程序中出现的常量都 可以静态分配。 声明在函数外面
12
2015-4-21
9.2 存储组织
9.2.1 运行时内存的划分 9.2.2 活动记录 9.2.3 局部数据的组织 9.2.4 全局存储分配策略
2015-4-21
13
7.2.1 运行时内存的划分
目标代码 静态数据 栈 空闲 空间 堆
2015-4-21 14
9.2.2 活动记录
过程的每个活动所需要的信息用一块连续的存储 区来管理,这块存储区叫做活动记录 假定语言的特点为:允许过程递归调用、允许过程 含有可变数组,过程定义允许/不允许嵌套。
2015-4-21
静态链
动态链 返回地址
返回地址 动态链:指向调用该 过程前的最新活动记 录地址的指针。 静态链:指向静态直接 外层最新活动记录地址的 指针,用来访问非局部数 据。
17
每个过程的活动记录内容
TOP 临时变量 数组内情向量 局部变量 形式单元
2 1
SP 0
静态链 动态链 返回地址
9.3 静态存储分配策略
Fortran语言被设计成允许静态存储分配
cnsume的代码 代码
prduce的代码
character 50 buf integer next character c character 80 buffer integer next cnsume的活动记录 静态数据 prduce的活动记录
School of Computer Science & Technology Harbin Institute of Technology
第9章 运行时的存储组织
解决问题:符号空间到地址空间的映射问题 重点:符号表的内容、组织,过程调用实现,
静态存储分配、动态存储分配的基本
方法。
难点:活动记录、非局部数据的栈实现 问题
当过程名出现在可执行语句中时,称相应的 过程在该点被调用。 过程调用就是执行被调用过程的过程体。
2015-4-21
某分段式程序运行时的内存划分
指令代码 常数 程序段1 程序段2 …… 程序段i …… 程序段n 公用数据 临时变量 数组 简单变量 形式单元 寄存器保护区 返回地址 程序段i的活动记录
25
局 部 数 据 区
2015-4-21
静态存储分配策略
顺序分配算法(基于调用图)
按照程序段出现的先后顺序逐段分配 1/22 2/15 3/18
2015-4-21 21
9.2.3 局部数据的组织
在 X86/Linux 机器的结果和 SPARC/Solaris 工作 站不一样,是20和16。 typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 12 double f;8 }a; }b;
9.3 静态存储分配策略
(1)PROGRAM CNSUME (2) CHARACTER *50 BUF (3) INTEGER NEXT (4〕 CHARACTER C,PRDUCE (5) DATA NEXT/1/,BUF/ ' '/ (6) C=PRDUCE()。 (7) BUF(NEXT:NEXT)=C (8〕 NEXT=NEXT+1 (9) IF(C.NE.' ' )GOTO 6 (10) WRITE(*,'(A)')BUF (11) END
10
2015-4-21
9.1.4 参数传递方式
信息交换方式 传统程序设计语言过程间交换信息的方法通 常是通过非局部名字和被调用过程的参数来 实现的。
传值 传地址 传值结果 传名
其主要区别在于实参所代表的究竟是左值、右 值还是实参的正文本身 2015-4-21 11
编译程序组织存储空间时必须考虑的问 题
2015-4-21 22
9.2.4 全局存储分配策略
静态存储分配策略(FORTRAN)
如果在编译时能确定数据空间的大小,则可采用 静态分配方法:在编译时刻为每个数据项目确定 出在运行时刻的存储空间中的位置。
动态存储分配策略(PASCAL,C)
如果在编译时不能确定运行时数据空间的大小, 则必须采用动态分配方法。允许递归过程及动态 申请、释放内存。 栈式动态存储分配 堆式动态存储分配
程序段
6 7/80 5
区域
0~9 0~22
4
3
0~16
23~40 17~31 41~62
27
4/17
6/10
5/23
2 1
思考:如何设计分配算法?
2015-4-21
共需要63个存储单元
9.3 静态存储分配策略
静态分配给语言带来的限制 不允许递归过程 数据对象的长度和它在内存中位置的限制, 必须是在编译时可以知道的 数据结构不能动态建立 例:一个Fortran 77程序
环境把名字映射到左值,而状态把左值映射到右值 赋值改变状态,但不改变环境。
如果环境将名字x映射到存储单元s,我们就说x 被绑定到s
环境 状态
名字
2015-4-21
内存位置 (变量)
值
5
9.1.2 声明的作用域
声明的作用域 是指程序中的这样一段区域,在该区域中,x 的引用均指向x的这一声明。 静态作用域和动态作用域 对于某种程序设计语言,如果只通过考察其程 序就可以确定某个声明的作用域,则称该语 言使用静态作用域; 否则称该语言使用动态作用域
过程能否递归? 当控制从过程的活动返回时,局部变量的值是否要 保留? 过程能否访问非局部变量? 过程调用的参数传递方式? 过程能否作为参数被传递? 过程能否作为结果值传递? 存储块能否在程序控制下动态地分配? 存储块是否必须显式地释放? 这些问题都对存贮分配策略有着直接的影响!
第9章 运行时的存储组织
9.1 与存储组织有关的源语言概念与特征 9.2 存储组织 9.3 静态存储分配 9.4 栈式存储分配 9.5 栈中非局部数据的访问 9.6 堆管理 9.7 本章小结
2015-4-21 2
9.1 与存储组织有关的源语言概念与特征
编译程序必须准确地实现包含在源程序中的 各种抽象概念 各种抽象概念,如名字、作用域、数据类型、 操作符、过程、参数和控制流结构等,
采用栈式存储分配机制 活动记录:运行时,每当进入一个过程就有一个 相应的活动记录压入栈顶。 活动记录一般含有连接数据、形式单元、局部变 量、局部数组的内情向量和临时工作单元等。
15
2015-4-21
每个过程的活动记录内容
——非嵌套语言(如C)
TOP 临时变量 数组内情向量 简单变量 形式单元
2015-4-21 20
9.2.3 局部数据的组织
在 SPARC/Solaris工作站上下面两个结构的 size 分别是24和16,为什么不一样? typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 16 double f;8 }a; }b;
9.3 静态存储分配策略
(12)CHARACTER FUNCTION PRDUCE() (13) CHARACTER * 80 BUFFER (14) INTEGER NEXT (15) SAVE BUFFER,NEXT (16) DATA NEXT/81/ (17) IF(NEXT.GT.80)THEN (18) READ(*,'(A)')BUFFER (19) NEXT=1 (20) END IF (21) PRDUCE=BUFFER(NEXT:NEXT) (22 ) NEXT=NEXT+1 (23 ) END
6
2015-4-21
9.1.2 声明的作用域
作用域的显式控制 C++、Java和C#等使用public、private和 protected这样的关键字,对作用域进行显式控 制。 声明的作用域是通过符号表进行管理的
2015-4-21
7
9.1.3 过程及其活动
将“过程、函数和方法”统称为“过程” 过程定义是一个声明,它的最简单形式是把 一个标识符和一个语句联系起来。 该标识符是过程名,而这个语句是过程体。
2015-4-21
23
9.3 静态存储分配策略
如果在编译时就能确定一个程序在运行时所需 要的存储空间的大小,则在编译时就能安排好 目标程序运行时的全部数据空间,并能确定每 个数据项的地址,存储空间的这种分配方法称 为静态存储分配。必须满足如下条件:
数据对象的长度和它在内存中的位置在编译时必须 是已知的; 不允许过程的递归调用,因为一个过程的所有活动 都是用同样的局部名字绑定的; 数据结构不能动态建立,因为没有运行时的存储分 配机制。
2 1
SP 0
2015-4-21
参数个数 返回地址 旧SP
对任何局部变量X的引 用可表示为变址访问: dx[SP] dx:变量X相对于活动记 录起点的地址,在编译 时可确定。
16
每个过程的活动记录内容
——嵌套语言(如Pascal)
TOP 临时变量 数组内情向量
连接数据
局部变量
形式单元 2 1 SP0
9.3 静态存储分配策略
C 语言程序的全局变量和程序中出现的常量都 可以静态分配。 声明在函数外面
12
2015-4-21
9.2 存储组织
9.2.1 运行时内存的划分 9.2.2 活动记录 9.2.3 局部数据的组织 9.2.4 全局存储分配策略
2015-4-21
13
7.2.1 运行时内存的划分
目标代码 静态数据 栈 空闲 空间 堆
2015-4-21 14
9.2.2 活动记录
过程的每个活动所需要的信息用一块连续的存储 区来管理,这块存储区叫做活动记录 假定语言的特点为:允许过程递归调用、允许过程 含有可变数组,过程定义允许/不允许嵌套。
2015-4-21
静态链
动态链 返回地址
返回地址 动态链:指向调用该 过程前的最新活动记 录地址的指针。 静态链:指向静态直接 外层最新活动记录地址的 指针,用来访问非局部数 据。
17
每个过程的活动记录内容
TOP 临时变量 数组内情向量 局部变量 形式单元
2 1
SP 0
静态链 动态链 返回地址
9.3 静态存储分配策略
Fortran语言被设计成允许静态存储分配
cnsume的代码 代码
prduce的代码
character 50 buf integer next character c character 80 buffer integer next cnsume的活动记录 静态数据 prduce的活动记录
School of Computer Science & Technology Harbin Institute of Technology
第9章 运行时的存储组织
解决问题:符号空间到地址空间的映射问题 重点:符号表的内容、组织,过程调用实现,
静态存储分配、动态存储分配的基本
方法。
难点:活动记录、非局部数据的栈实现 问题
当过程名出现在可执行语句中时,称相应的 过程在该点被调用。 过程调用就是执行被调用过程的过程体。