编译器设计-RunTime运行时环境
编译器设计-RunTime运行时环境
Compiler Design - Run-Time Environment
作为源代码的程序仅仅是文本(代码、语句等)的集合,要使其活动,它需要在目标计算机上执行操作。程序需要内存资源来执行指令。程序包含程序名、标识符等,运行时需要与实际内存位置进行映射。
所谓运行时,我们指的是正在执行的程序。运行时环境是目标机器的一种状态,它可以包括软件库、环境变量等,为系统中运行的进程提供服务。
运行时支持系统是一个包,主要由可执行程序本身生成,有助于进程与运行时环境之间的进程通信。它在执行程序时负责内存分配和取消分配。
激活树Activation Trees
程序是一系列指令组合成若干过程的序列。过程中的指令是按顺序执行的。过程有一个开始和结束分隔符,其中的所有内容都称为过程的主体。过程标识符及其内部的有限指令序列构成了过程的主体。
过程的执行称为其激活。激活记录包含调用过程所需的所有必要信息。激活记录可以包含以下单元(取决于使用的源语言)。
每当执行一个过程时,它的激活记录都存储在堆栈上,也称为控制堆栈。当一个过程调用另一个过程时,调用方的执行将被挂起,直到被调用的过程完成执行为止。此时,被调用过程的激活记录存储在堆栈上。
我们假设程序控制按顺序执行,当一个过程被调用时,它的控制权被转移到被调用的过程。当被调用的过程被执行时,它将控件返回给调用方。这种类型的控制流使以树(称为激活树)的形式表示一系列激活变得更容易。
为了理解这个概念,我们以一段代码为例:
. . .
printf(“Enter Your Name: “);
scanf(“%s”, username);
show_data(username);
printf(“Press any key to continue…”);
. . .
int show_data(char *user)
{
printf(“Your name is %s”, username);
return 0;
}
. . .
下面是给定代码的激活树。
现在我们知道过程是以深度优先的方式执行的,因此堆栈分配是过程激活的最佳存储形式。
存储分配Storage Allocation
运行时环境管理以下实体的运行时内存需求:
代码:它被称为程序的文本部分,在运行时不会更改。它的内存需求在编译时是已知的。
过程:它们的文本部分是静态的,但它们是以随机的方式调用的。这就是为什么堆栈存储用于管理过程调用和激活。
变量:变量只有在运行时才知道,除非它们是全局变量或常量。堆内存分配方案用于管理运行时变量的内存分配和取消分配。
静态分配Static Allocation
在这种分配方案中,编译数据被绑定到内存中的一个固定位置,并且在程序执行时不会改变。由于预先知道内存需求和存储位置,因此不需要内存分配和取消分配的运行时支持包。
堆栈分配Stack Allocation
过程调用及其激活通过堆栈内存分配进行管理。它适用于后进先出(LIFO)方法,这种分配策略对于递归过程调用非常有用。
Heap Allocation
仅在运行时才分配和取消分配过程本地的变量。堆分配用于动态地将内存分配给变量,并在不再需要变量时将其收回。
除了静态分配的内存区域外,堆栈和堆内存都可以动态和意外地增长和收缩。因此,不能在系统中为它们提供固定数量的内存。
如上图所示,代码的文本部分被分配了固定数量的内存。堆栈和堆内存被安排在分配给程序的总内存的最末端。两个人都在互相残杀和成长。
参数传递Parameter Passing
过程之间的通信媒介称为参数传递。调用过程中的变量值通过某种机制传递给被调用过程。在继续之前,先复习一些与程序中的值有关的基本术语。
右值
表达式的值称为其r值。如果包含在单个变量中的值出现在赋值运算符的右侧,则该值也将变为r值。r值总是可以分配给其他变量。
l值
存储表达式的内存(地址)的位置称为该表达式的l值。它总是出现在赋值运算符的左侧。
For example:
- day = 1;
- week = day * 7;
- month = 1;
- year = month * 12;
从这个例子中,我们了解到常数值(如1、7、12)和变量(如日、周、月和年)都有r值。只有变量才有l值,因为它们也表示分配给它们的内存位置。
For example:
- 7 = x + y;
是一个l值错误,因为常量7不代表任何内存位置。
形式参数Formal Parameters
接受调用方过程传递的信息的变量称为形式参数。这些变量在被调用函数的定义中声明。
实际参数Actual Parameters
将其值或地址传递给被调用过程的变量称为实际参数。这些变量在函数调用中指定为参数。
Example:
- fun_one()
- {
- int actual_parameter = 10;
- call fun_two(int actual_parameter);
- }
- fun_two(int formal_parameter)
- {
- print formal_parameter;
- }
形式参数保存实际参数的信息,这取决于所使用的参数传递技术。它可以是一个值或地址。
传递值Pass by Value
在传递值机制中,调用过程传递实际参数的r值,编译器将其放入被调用过程的激活记录中。然后,形式参数保存调用过程传递的值。如果形式参数所保留的值发生了更改,则不会对实际参数产生影响。
通过引用传递Pass by Reference
在按引用传递机制中,实际参数的l值被复制到被调用过程的激活记录中。这样,被调用的过程现在拥有实际参数的地址(内存位置),而形式参数引用相同的内存位置。因此,如果更改了形式参数所指向的值,则应该看到对实际参数的影响,因为它们也应该指向相同的值。
按副本传递还原Pass by Copy-restore
此参数传递机制的工作原理与“按引用传递”类似,只是在调用过程结束时对实际参数进行更改。在函数调用时,实际参数的值被复制到被调用过程的激活记录中。如果操作了形式参数,则对实际参数没有实时影响(因为传递了l值),但是当调用过程结束时,形式参数的l值将复制到实际参数的l值。
例子:
Example:
- int y;
- calling_procedure()
- {
- y = 10;
- copy_restore(y); //l-value of y is passed
- printf y; //prints 99
- }
- copy_restore(int x)
- {
- x = 99; // y still has value 10 (unaffected)
- y = 0; // y is now 0
- }
此函数结束时,形式参数x的l值复制到实际参数y,即使在过程结束前改变了y值,x的l值也复制到y的l值,使其行为类似于通过引用调用。
按名称传递Pass by Name
像Algol这样的语言提供了一种新的参数传递机制,其工作原理类似于C语言中的预处理器。在按名称传递机制中,被调用的过程的名称将被其实际主体替换。Pass by name以文本方式将过程调用中的参数表达式替换为过程主体中的相应参数,以便它现在可以处理实际参数,这与Pass by reference非常类似。
编译器设计-RunTime运行时环境的更多相关文章
- 运行时环境(The Runtime Environment)
App Engine应用响应网络请求.当一个客户端(典型的是用户的Web浏览器)使用HTTP请求(比如获取在URL上的网页)连接上应用的时候,网络请求就开始了.当App Engine接收到请求时,它会 ...
- java 运行时环境和编译器环境
必须要保证运行环境高于编译环境 1.编译器的环境设置 单击项目右键-> Properties -> Java Compiler -> 5或6 如果编译器的环境高于运行时环境会报错. ...
- java 常用类库:操作系统System类,运行时环境Runtime
System类: System 类代表Java程序的运行平台,程序不能创建System类的对象, System类提供了一些类变量和类方法,允许直接通过 System 类来调用这些类变量和类方法. Sy ...
- iOS开发——高级特性&Runtime运行时特性详解
Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 ...
- Runtime运行时的那点事儿
注:本文是对 Colin Wheeler 的 Understanding the Objective-C Runtime 的翻译. 初学 Objective-C(以下简称ObjC) 的人很容易忽略一个 ...
- Java运行时环境---内存划分
背景:听说Java运行时环境的内存划分是挺进BAT的必经之路. 内存划分: Java程序内存的划分是交由JVM执行的,而不像C语言那样需要程序员自己买单(C语言需要程序员为每一个new操作去配对del ...
- ios - runtime运行时应用---交换方法
runtime运行时用法之一 --- 交换类的方法,此处简单写了把系统的UIView的setBackgroundColor的方法换成了自定义的pb_setBackgroundColor 首先创建UIV ...
- runtime 运行时机制 完全解读
runtime 运行时机制 完全解读 目录[-] import import 我们前面已经讲过一篇runtime 原理,现在这篇文章主要介绍的是runtime是什么以及怎么用!希望对读者有所帮助! ...
- Apache Flink 分布式运行时环境
Tasks and Operator Chains(任务及操作链) 在分布式环境下,Flink将操作的子任务链在一起组成一个任务,每一个任务在一个线程中执行.将操作链在一起是一个不错的优化:它减少了线 ...
随机推荐
- Python中面向对象和类
目录 面向对象 类的定义 类的访问 类的属性和方法 继承和多态 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的. 面向对象: 类(C ...
- 逆向 stdio.h 函数库 fseek 函数(调试版本)
0x01 fseek 函数 函数原型:int fseek(FILE *stream, long int offset, int whence) 函数功能:设置流 stream 的文件位置为给定的偏移 ...
- Cauchy-Binet 公式的应用
Binet-Cauchy 公式 我们知道,方阵的行列式不是方阵的线性函数,即对 \(\forall \lambda\in F,A,B\in F^{n\times n}\),有 \(det(A+B)\n ...
- JAVA的安装
1.从JAVA官网 下载 注意选择自己需要的版本 2.百度云盘 链接:https://pan.baidu.com/s/1deOFGN1xB0mgz6s2mTRXdA 提取码:ke97 安装JAVA J ...
- vscode 终端操作命令npm报错
错误: 如果没有安装的node.js ,则需要安装. node.js官网下载地址: https://nodejs.org/zh-cn/ 安装node.js 后会看到C:\Users\XXX\AppDa ...
- Elasticsearch入门,看这一篇就够了
目录 前言 可视化工具 kibana kibana 的安装 kibana 配置 kibana 的启动 Elasticsearch 入门操作 操作 index 创建 index 索引别名有什么用 删除索 ...
- 如何解决 shell 脚本重复执行的问题
在开发过程中,经常会使用shell脚本去完成定时备份的任务,普遍的做法是通过系统的定时任务定时执行备份脚本 设想这样一种场景,本次备份时间到了,自动执行备份脚本,如果备份比较耗时的话,会一直持续到下一 ...
- Promise解析(待完成)
Promise是一种异步操作的解决方案,将写法复杂的传统的回调函数和监听事件的异步操作,用同步代码的形式表达出来.避免了多级异步操作的回调函数嵌套. 1.主要用于异步计算 2.可以将异步操作队列化,按 ...
- 3D高清电商购物小图标图片_在线商城三维icon图标素材大全
3D高清电商购物小图标图片_在线商城三维icon图标素材大全
- [Linux] 完全卸载mysql
参考 https://www.jianshu.com/p/ef58fb333cd6