编译原理第10章运行时的存储组织与分配
编译原理运行时存储空间的组织和管理课件

变量和数据的存储
• 静态存储:在编译时分配固定大小的内存空间。 • 动态存储:在运行时动态地分配和释放内存空间。 • 数据对齐:为了提高访问效率,对变量在内存中的位置进行调整。 • 在程序中,变量和数据的存储方式通常分为静态存储和动态存储两种。静态存
储是指在编译时就为变量分配固定大小的内存空间,这种方式适用于在程序执 行期间大小不变的变量。而动态存储是在运行时动态地为变量分配和释放内存 空间,它适用于大小在运行时才能确定或者在程序执行过程中会发生变化的数 据结构。为了提高内存访问效率,编译器通常还会进行数据对齐操作,即调整 变量在内存中的位置,使其按照特定的字节边界对齐,这样可以减少CPU访 问内存的次数,提高程序的执行速度。
04 数据段和代码段 的管理
数据段的组织和管理
静态存储分配:在编译时确定变量的 存储空间需求,并为其分配固定的存 储空间。这种分配方式适用于全局变 量和静态变量,其存储空间通常位于 数据段中。
动态存储分配:在运行时根据程序的 需要动态地分配存储空间。这种方式 适用于局部变量和临时变量,其存储 空间通常位于栈或堆中。动态存储分 配能够更有效地利用存储空间,并根 据需要动态调整。
03 堆区和栈区的管 理
堆区的组织和管理
动态内存分配
内存碎片问题
堆区是程序中用于动态内存分配的区 域,使用堆区可以实现在运行时根据 需要动态地分配和释放内存空间。在 堆区中,内存块的大小和数量是灵活 的,可以根据程序的需求进行调整。 常用的动态内存分配函数包括 malloc()和new()。
由于堆区的动态分配特性,频繁地分 配和释放内存块可能会导致内存碎片 问题。内存碎片指的是堆区中无法被 有效利用的小块内存空间。为了解决 这个问题,可以采用内存池技术,预 先分配一大块内存空间,并将其划分 为多个小块,每次需要分配内存时, 从内存池中获取一块合适的内存块。
第10章目标程序运行时的存储组织

p3活动记录 存取链(静态链) 控制链(动态链)
p3活动记录 存取链(静态链) 控制链(动态链)
main活动记录
2、用Display表
Display表---嵌套层次显示表 当前激活过程的层次为K,它的Display表含有K+1个
单元,依次存放着现行层,直接外层…直至最外层的每 一过程的最新活动记录的基地址。 说明:1、由于过程的层数可以静态确定,因此每个过程 的Display表的体积在编译时即可以确定。
Q的 活动记录
P的 活动记录 主程序的 活动记录
DISPLAY表பைடு நூலகம்维护和建立
为便于组织存储区,将display作为活动记录的一 部分,其相对地址在编译时是完全可以确定的。
假设过程P1可调用P2,为了能在P2中建立P2的 display,在P1调用P2时设法把P1的display地址 作为连接数据之一(全局display地址)传送给P2, 因此连接数据包括: 老SP值(动态链) 返回地址 全局display地址
嵌套过程的栈式分配方案
分程序结构的存储分配方案
3、过程活动:一个过程的活动指的是该过程的一次执行。
4、活动记录:一个过程的一次执行所需要的信息使用一个连 续的存储区来管理,这个区(块)叫做一个活动记录。
活动记录一般包含:
(1)连接数据
返回地址—调用过程指令的下一条指令的地址。
动态链(控制链)—指向调用该过程活动记录地址的指针。用 于当调用返回时,将当前栈顶正确切换到调用者的活动记录
2、某过程p是在层次为i的过程q内定义的,并且q是 包围p的直接外层,那么p的过程层数为i+1。
例: program main(i,0);
编译原理目标程序运行时的存储组织

编译原理目标程序运行时的存储组织引言在编译原理中,目标程序是指通过编译器将高级源代码转换为机器可执行的程序。
在目标程序运行时,需要一定的存储空间来存储程序的指令和数据。
本文将介绍编译原理中目标程序运行时的存储组织的基本概念和原理。
程序的内存模型目标程序在运行时的存储组织是通过内存模型来描述的。
内存模型定义了目标程序在内存中的存储方式和访问机制。
常见的内存模型有栈式模型、堆式模型和段式模型等。
栈式模型栈式模型将程序的内存划分为栈和堆两部分。
栈用于存储程序的局部变量、函数调用和返回地址等信息,而堆用于动态存储分配,如动态创建的对象以及通过malloc等函数分配的内存。
栈式模型的存储空间是连续分配的,栈的大小是固定的,而堆的大小可以根据需要进行动态调整。
堆式模型堆式模型将程序的内存划分为堆和栈两部分。
堆是动态分配的内存空间,用于存储程序运行时动态创建的对象和变量。
栈则用于存储函数调用的临时变量、函数参数和返回地址等信息。
堆式模型的存储空间可以动态调整,但需要手动管理内存的分配和释放,以避免内存泄漏和内存碎片的产生。
段式模型段式模型将程序的内存划分为若干个段,每个段用于存储特定类型的数据。
常见的段包括代码段、数据段、堆段和栈段等。
代码段用于存储程序的指令,数据段用于存储常量、全局变量和静态变量等数据,堆段和栈段与堆式模型和栈式模型类似。
段式模型可以更灵活地管理不同类型的数据,提高了内存的利用率。
存储器分配在目标程序运行时,编译器负责将程序的指令和数据分配到合适的存储器中。
存储器分配的主要目标是提高程序的执行效率和优化存储空间的利用率。
静态存储器分配静态存储器分配是在编译时确定存储器的分配方式。
静态存储器分配将程序的指令和数据分配到固定的内存地址上,程序运行时不会改变存储器分配。
静态存储器分配适用于程序结构稳定、数据量较小的场景,但难以适应动态创建和销毁对象的情况。
栈式存储器分配栈式存储器分配将程序的局部变量、函数调用和返回地址等信息存储在栈中。
编译原理第10章 存储组织

存储分配结构图
若主程序调用了过程Q,Q又调用了R,在R进入运行后的存 储结构如图(a)所示。
若主程序调用了过程Q,Q递归调用自己,在Q过程第二次进 入运行后的存储结构如图(b)所示。
若主程序先调用过程Q,然后主程序接着调用R,且Q过程不 调用Q和R,这时Q和R进入运行后的存储结构分别如图(c)和 (d)所示。
栈式存储分配的实现
过程的活动记录 简单的栈式动态分配实现 嵌套过程语言的栈式实现 分程序结构的存储管理
过程的活动记录
过程的活动记录是 一段连续的存储 区.用以存放过程 的一次执行所需要 的信息。
简单描述
简单描述
1.临时工作单元,比如计算表达式过程中需存放中间结果用 的临时值单元。
2.局部变量,一个过程的局部变量。 3 .保存机器状态,容纳该过程执行前关于机器状态信息,
另一部分则是用以管理过程活动的记录信息,即当一次过程调用出现 时,调用该过程的那个过程的活动即被中断,当前机器的状态信息, 诸如程序计数器(返回地址)、寄存器的值等等,也都必须保留在栈中。
当控制从调用返回时,便根据栈中记录的信息恢复机器状态, 使该过程的活动重新开始。
堆式动态存储分配
如果一个程序语言提供用户自由地申请数据空间和退还数据空间的机制 (如C++中的new,delete.Pascal的new,便是这种机制),或者不仅有过 程而且有进程的程序结构,即空间的使用未必服从“先申请后释放,后 申请先释放”的原则,那么栈式的动态分配方案就不适用了。这种情况 下通常使用一种称为堆式的动态存储分配方案。
第二,当从内层分程序向外转移时可能同时 要结束若干个分程序,恢复所要到达的那个 分程序的数据区需要顺序退出,浪费时间, 降低效率。
第10章目标程序运行时的存储组织

这里是传值)
第10章目标程序运行时的存储组织
(1)program reference(input,output);
(2)var a,b:integer;
(3)procedure swap({var} x,y:integer);
第10章目标程序运行时的存储组织
第10章目标程序运行时的存储组织
嵌套过程语言的栈式 分配方案
主要特点:
• (语言)一个过程可以引用包围它的任 一外层过程所定义的标识符(如变量, 数组或过程等)。
• (实现)一个过程可以引用它的任一外 层过程的最新活动记录中的某些数据。
第10章目标程序运行时的存储组织
第10章目标程序运行时的存储组织
(1)swap(x,y)
(2)int *x,*y;
(3){ int temp;
(4)
temp=*x; *x=*y; *y=temp;
(5)}
(6)main( )
(7){ int a=1,b=2;
(8) swap(&a,&b);
(9) printf(“a is now %d,b is now %d\n”,a,b);
(4) var temp:integer;
(5) begin
(6)
temp:=x;
(7)
x:=y;
(8)
y:=temp
(9) end;
(10)begin
(11) a:=1; b:=2;
(12) swap(a,b);
(13) writeln(‘a=‘,a);writeln(‘b=‘,b)
(14)end.
编译原理实践8—运行时的存储组织与分配汇总

2.数据存储器的动态存储器管理
每一个PL/0过程可能含有局部变量。过程可以 递归调用,每次递归调用,被调用过程又要求 有自己的局部变量,因此不可能在编译时就为 局部变量确定好固定的存储位置。只能在每次 执行过程调用时才为过程的一组局部变量确定 相应的存储位置。过程一结束,存储位置又被 释放。 后进先出—last in first out 按照栈的原理来管理数据存储器
PL/0数据动态存储采用的技术措施
1. 编译时为每一变量名、过程名和程序段确定一个反映 静态嵌套深度的级别level 2. 调用一个过程时,把他的活动记录压入运行时的栈顶, 返回时弹出相应的活动记录。活动记录包括:
1. 2. 3. 4.
静态链接SL:指向定义该过程的直接外层过程的活动记录的 基地址,以确保变量的正确存取 动态链接DL:指向调用该过程前正在运行的那个过程的活动 纪录的基地址,以确保能返回到调用过程段 返回地址RA:保存该被调用过程返回后的地址,也就是调用 过程指令的下一条指令的地址 为过程局部变量预留的存储单元
4. 所有运算操作都从栈顶找到它的操作数,并 以计算结果代之
3.目标计算机指令系统及其解释
表10-1 P137
4.解释程序interpret及其执行
Program6.pas 解释程序interpret
2)嵌套过程语言的栈式存储分配
嵌套过程语言:允许过程嵌套,如 pascal,PL/0。AR中必须有一些内容,用于解 决对非局部变量的引用问题 “嵌套层次”,或称层数。主程序为0,过程S 在层数为i的过程R定义,则S层数为i+1 一个过程可以引用包围它的任一外层过程所定 义的变量,解决方法很多,常见的方法:双指 针方法和Display表方法 双指针方法简单直接,但当嵌套层次较多时, 对非局部量的访问效率较低! Display表方法效率较高,实现略复杂 对于PL/0的编译程序,采用的是双指针方法
第10章 运行时的存储组织与分配

Fall 2010li weihuaDepartment of Computer Science & technology, Informationalschool, Yunnan University Compilers :Principles and Techniques Chapter 10 Run-Time Environments运行时存储组织的作用与任务 程序在存储器中的布局存储分配策略活动记录运行时存储组织的作用与任务−代码生成前如何安排目标机资源的使用−几个问题•数据表示如何在目标机中表示每个源语言类型的值•存储分配如何组织不同作用域变量的存储•过程实现如何实现过程/函数调用,参数传递代码生成前需要安排目标机资源的使用−代码生成的实质•建立如下关联/绑定(biding)源程序/中间代码的脚本↔运行时的脚本源程序/中间代码的名字↔运行时的存储−目标机资源的使用•内存/缓存:存放目标代码和数据(包括系统数据)•寄存器:存放控制信息和数据信息(常为中间信息)•操作系统资源数据表示−源程序中数据对象在内存或寄存器中的表示形式•源程序中数据对象的属性名字(name),类型(type),值(value),成员(component),偏移地址(offset),……•数据对象在内存或寄存器中的表示形式位、字节、字、字节序列、……•有些机器要求数据存放时要按某种方式对齐(align)如:要求所有数据存放的起始地址为能够被4整除数据表示举例−基本类型数据char 数据 1 byte integer 数据 4 bytesfloat 数据8 bytes boolean数据 1 bit / 1 byte 指针 4 bytes数组一块连续的存储区(按行/列存放)结构/记录所有域(field)存放在一块连续的存储区存储分配策略−静态分配•在编译期间为数据对象分配存储−动态分配•栈式分配将数据对象的运行时存储按照栈的方式来管理•堆式分配从数据段的堆空间分配和释放数据对象的运行时存储静态存储分配−在编译期间就可确定数据对象的大小•不宜处理递归过程或函数−某些语言中所有存储都是静态分配•如汇编语言,FORTRAN语言−多数语言只有部分存储进行静态分配•可静态分配的数据对象如大小固定且在程序执行期间可全程访问的全局变量,以及程序中的常量(literals,constants)•如C 语言中的static和extern变量栈式存储分配−用于有效实现层次嵌套的程序结构•如实现过程/函数,块层次结构−可以实现递归过程/函数•比较:静态分配不宜实现递归过程/函数−运行栈中的数据单元是活动记录(activation record)(专门介绍)堆式存储分配−从堆空间为数据对象分配/释放存储•灵活数据对象的存储分配和释放不限时间和次序−显式的分配或释放(explicit allocation / dealocation)•程序员负责应用程序的(堆)存储空间管理(借助于)编译器和运行时系统所提供的默认存储管理机制)−隐式的分配或释放(implicit allocation / dealocation)•(堆)存储空间的分配或释放不需要程序员负责,由编译器和运行时系统自动完成堆式存储分配−某些语言有显式的堆空间分配和释放命令•如:Pascal 中的new, depositC++ 中的new, delete•比较:C 语言没有堆空间管理机制,malloc()和free()是标准库中的函数,可以由library vendor提供−某些语言支持隐式的堆空间释放−不释放堆空间的方法z只分配空间,不释放空间,空间耗尽时停止z适合于堆数据对象多数为一旦分配,永久使用的情形z在虚存很大及无用数据对象不致带来很大零乱的情形也可采用运行时存储组织堆式存储分配−显式释放堆空间的方法•用户负责清空无用的数据空间(通过执行释放命令)•堆管理程序只维护可供分配命令使用的空闲空间•问题:可能导致灾难性的dangling pointer错误例:Pascal 代码片断C++ 代码片断var p,q: ^real; …new(p);q:=p; dispose(p);q^:=1.0;float * p,*q; …p=new float; q=p;delete p;*q:=1.0;堆式存储分配−堆空间的管理•分配算法面对多个可用的存储块,选择哪一个如:最佳适应算法(选择浪费最少的存储块)最先适应算法(选择最先找到的足够大的存储块)循环最先适应算法(起始点不同的最先适应算法)•碎片整理算法压缩合并小的存储块,使其更可用(可以分专门的话题讨论,超出本课程范围)(部分内容可参考数据结构和操作系统课程)活动记录−嵌套过程语言的栈式分配•主要问题解决对非局部量的引用(存取)•解决方案采用Display 寄存器表为活动记录增加静态链域活动记录−嵌套过程语言的栈式分配•采用Display 寄存器表Display 寄存器表(简称Display 表)记录各嵌套层当前过程的活动记录在运行栈上的起始位置(基地址)当前激活过程的层次为K(主程序的层次设为0),则对应的Display 表含有K+1 个单元,依次存放着现行层,直接外层…直至最外层的每一过程的最新活动记录的基地址嵌套作用域规则确保每一时刻Display 表内容的唯一性Display 表的大小(即最多嵌套的层数)取决于实现活动记录−嵌套过程语言的栈式分配•采用静态链(static link)Display 表的方法要用到多个寄存器,有时并不情愿这样做(寄存器资源很宝贵),一种可选的方法是采用静态链,只保留一个寄存器(即SP)指向当前AR所有活动记录都增加一个静态链(如在offset为0 处)的域,指向定义该过程的直接外过程(或主程序)运行时最新的活动记录在过程返回时当前AR 要被撤销,为回卷(unwind)到调用过程的AR(恢复SP),还需增加一个动态链过程调用与参数传递−参数传递方式•传值call-by-value传递的是实际参数的右值(r-value)•传地址call-by-reference(-address, -location)传递的是实际参数的左值(l-value)−注表达式的左值代表存储该表达式值的地址表达式的右值代表该表达式的值过程调用与参数传递−参数传递方式•实现call-by-value形式参数当作过程的局部变量处理,即在被调过程的活动记录中开辟了形参的存储空间,这些存储位置用以存放实参调用过程计算实参的值,将其放于对应的存储空间被调用过程执行时,就像使用局部变量一样使用这些形式单元过程调用与参数传递−参数传递方式•实现call-by-reference把实在参数的地址传递给相应的形参,即调用过程把一个指向实参的存储地址的指针传递给被调用过程相应的形参:若实在参数是一个名字,或具有左值的表达式,则传递左值若实在参数是无左值的表达式,则计算值,放入一存储单元,传此存储单元地址That’s all for today.Thank You。
编译原理程序运行时的存储组织

编译原理程序运行时的存储组织一、程序的应该存储区域1.代码区:也称为文本区或者只读区,用于存放程序的目标代码。
代码区是只读的,不允许修改。
在程序运行过程中,代码区的内容不会发生变化。
2.全局数据区:用于存放全局变量和静态数据。
全局数据区在程序开始运行时就被分配好空间,在程序的整个运行过程中都存在,直到程序结束。
3.堆区:用于存放动态分配的内存空间,也称为动态内存分配区。
堆区的内存空间是在程序运行时动态分配和释放的,可以根据程序的需要进行扩大或者缩小。
4.栈区:用于存放函数的局部变量和函数调用信息。
栈区的空间是在程序运行时自动分配和释放的,由编译器负责管理。
在函数调用时,会为函数分配一块栈区空间,函数返回后,该空间被自动释放。
二、内存管理方式1.静态内存管理:静态内存管理是指在程序编译阶段,由编译器根据程序的静态内存需求,在编译过程中为程序分配好固定大小的内存空间,静态内存管理的特点是内存空间的分配和释放都是在编译时确定的,程序运行时不需要进行内存管理。
2.动态内存管理:动态内存管理是指在程序运行时根据需要动态地分配和释放内存空间,动态内存管理的特点是内存空间的分配和释放是在程序运行过程中动态确定的。
动态内存管理可以通过堆区进行。
三、内存分配和释放编译原理程序在运行时的存储组织中,对于静态内存区域的分配和释放是由编译器在编译时确定的,程序在运行时无法进行修改。
对于动态内存区域的分配和释放,可以通过堆区进行,可以使用以下几个函数进行动态内存的分配和释放:1. 分配内存:程序可以使用malloc函数、calloc函数或者realloc函数来分配内存空间。
malloc函数用于分配指定字节数的内存空间,calloc函数用于分配指定数量和大小的内存空间,realloc函数用于调整已经分配的内存空间的大小。
2. 释放内存:程序在使用完动态分配的内存空间后,需要使用free函数来释放内存空间。
free函数会将之前分配的内存空间标记为可用状态,可以供其他程序使用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
10.2 静态存储分配
在编译阶段由编译程序实现对存储空间的管理,为 源程序中的变量分配存储单元。
条件
➢在编译时能够确定变量在运行时的数据空间大小 ➢运行时不改变
编译原理第10章运行时的存储组织与 分配
FORTRAN程序的静态分配
编译原理第10章运行时的存储组织与 分配
动态存储分配 在目标程序运行阶段由目标程序实现对存
再见,see you again
2020/12/13
编译原理第10章运行时的存储组织与 分配
编译原理第10章运行时的存储组织与 分配
练习 下面程序的运行结果是什么?如果把第6行的(i+1)*fact( )改 成fact( )*(i+1)的话,则程序的运行结果是有什么变化?试分析 为什么会有这两种不同的结果。 int fact( ) { static int i=5; if(i==0) return 1; else { i--; return((i+1)*fact( )); //第6行 }} main( ) { printf("factor of 5!=%d\n",fact());}
为运行阶段实现存储奠定基础
编译原理第10章运行时的存储组织与 分配
教学内容
• 10.1 存储组织概述 • 10.2 静态存储分配 • 10.3 栈式动态存储分配 • 10.4 堆式动态存储分配
编译原理第10章运行时的存储组织与 分配
10.1 存储组织概述
运行时存储空间的划分
代码空间
目标代码空间 静态数据空间
储空间的组织与管理,为源程序中的变量分 配存储单元 特点 • 在目标程序运行时进行分配 • 编译时为运行阶段设计好存储组织形式,即为每个 数据项安排好它在数据区中的相对位置
编译原理第10章运行时的存储组织与 分配
10.3 栈式动态存储分配
变量生存期具有嵌套特性,即后进先出的特性(如递归) 进入时:在栈顶为其分配一个数据区 退出时:撤消过程数据区
编译原理第10章运行时的存储组织与 分配
10.4 堆式动态存储分配
变量生存期具有随机交叉特性,即非后进先出的特性(如程序 运行时动态申请存储空间) 给运行的程序划分一个大的存储区(称为堆) 每当需要时可从堆中分得一块 用完之后再退还给堆
编译原理第10章运行时的存储组织与 分配
3rew
演讲完毕,谢谢听讲!
编译原理第10章运行时 的存储组织与分配
2020/12/13
编译原理第10章运行时的存储组织与 分配
S.P 词法分析程序
符 号 表 管 理
语法分析程序 语义分析、生成中间代码
代码优化
ห้องสมุดไป่ตู้错 误 处 理
生成目标程序 O.P
编译程序在编译阶段要为源程序中出现的变量、常量等组
织好在运行阶段的存储空间
将这种组织形式通过生成的目标代码体现出来
栈
数据空间
自由空间
堆
编译原理第10章运行时的存储组织与 分配
过程的活动和活动记录
一个过程的活动:该过程的一次执行。 即每次执行一个过程体,就产生该过程的 一个活动。 活动记录:为了管理过程在一次执行中所 需要的信息,使用一段连续的存储区
编译原理第10章运行时的存储组织与 分配
活动记录的结构
编译原理第10章运行时的存储组织与 分配