编译器设计-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运行时环境的更多相关文章

  1. 运行时环境(The Runtime Environment)

    App Engine应用响应网络请求.当一个客户端(典型的是用户的Web浏览器)使用HTTP请求(比如获取在URL上的网页)连接上应用的时候,网络请求就开始了.当App Engine接收到请求时,它会 ...

  2. java 运行时环境和编译器环境

    必须要保证运行环境高于编译环境 1.编译器的环境设置 单击项目右键-> Properties -> Java Compiler -> 5或6 如果编译器的环境高于运行时环境会报错. ...

  3. java 常用类库:操作系统System类,运行时环境Runtime

    System类: System 类代表Java程序的运行平台,程序不能创建System类的对象, System类提供了一些类变量和类方法,允许直接通过 System 类来调用这些类变量和类方法. Sy ...

  4. iOS开发——高级特性&Runtime运行时特性详解

    Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 ...

  5. Runtime运行时的那点事儿

    注:本文是对 Colin Wheeler 的 Understanding the Objective-C Runtime 的翻译. 初学 Objective-C(以下简称ObjC) 的人很容易忽略一个 ...

  6. Java运行时环境---内存划分

    背景:听说Java运行时环境的内存划分是挺进BAT的必经之路. 内存划分: Java程序内存的划分是交由JVM执行的,而不像C语言那样需要程序员自己买单(C语言需要程序员为每一个new操作去配对del ...

  7. ios - runtime运行时应用---交换方法

    runtime运行时用法之一 --- 交换类的方法,此处简单写了把系统的UIView的setBackgroundColor的方法换成了自定义的pb_setBackgroundColor 首先创建UIV ...

  8. runtime 运行时机制 完全解读

    runtime 运行时机制 完全解读   目录[-] import import 我们前面已经讲过一篇runtime 原理,现在这篇文章主要介绍的是runtime是什么以及怎么用!希望对读者有所帮助! ...

  9. Apache Flink 分布式运行时环境

    Tasks and Operator Chains(任务及操作链) 在分布式环境下,Flink将操作的子任务链在一起组成一个任务,每一个任务在一个线程中执行.将操作链在一起是一个不错的优化:它减少了线 ...

随机推荐

  1. 认识二进制安全与漏洞攻防技术 (Windows平台)

    二进制漏洞是指程序存在安全缺陷,导致攻击者恶意构造的数据(如Shellcode)进入程序相关处理代码时,改变程序原定的执行流程,从而实现破坏或获取超出原有的权限. 0Day漏洞 在计算机领域中,0da ...

  2. 手动脱PeCompact 2.20壳实战

    作者:Fly2015 PeCompact壳又是一个没有听说过的壳,需要脱壳的程序是吾爱破解培训的第一课的选修作业四.最近对脱壳有点上瘾了,当然也遭受了脱壳受挫的无奈,但是比较幸运还是把这个壳给搞了. ...

  3. Sqli 注入点解析

    目录 Less-1: 字符型注入 Less-2: 数字型注入 Less-3: 单引号字符型+括号 Less-4: 双引号字符型+括号 Less-5: 单引号字符型+固定输出信息 (floor报错注入& ...

  4. POJ1258简单最小生成树

    #include<stdio.h> #include<algorithm> #define N (100 + 10) using namespace std; typedef ...

  5. Windows Pe 第三章 PE头文件(上)

    第三章  PE头文件 本章是全书重点,所以要好好理解,概念比较多,但是非常重要. PE头文件记录了PE文件中所有的数据的组织方式,它类似于一本书的目录,通过目录我们可以快速定位到某个具体的章节:通过P ...

  6. (Py练习)输出乘法口诀表

    #输出9*9乘法口诀表 for i in range(1,10): for j in range(1,i+1): print("%d*%d=%2d"%(i,j,i*j),end = ...

  7. Day009 稀疏数组

    稀疏数组(数据结构) 场景 需求:编写五子棋游戏中,有存盘和续上盘的功能. 分析问题:因为该二维数组的很多值默认都是0,因此记录了很多没有意义的数据. 解决:稀疏数组 稀疏数组介绍 当一个数组大部分元 ...

  8. 『政善治』Postman工具 — 10、Postman中对Cookie的操作

    目录 1.往常的Cookie处理方式 2.Postman中的Cookie管理机制 3.自定义Cookie管理内容 在接口测试中,某些接口的调用,需要带入已有Cookie,比如有些接口需要登陆后才能访问 ...

  9. .Net Core平台下,添加包的引用

    一个程序的开发过程中离不开对程序集(Assembly,将程序集打包好,就成为一个.dll的包文件,它也叫动态链接库(Dynamic Link Library​))的依赖,在以前ASP.Net时代,微软 ...

  10. ssh-的搭建和使用

    ssh的作用 : 可实现远程客户端登录服务器并对服务器的文件进行操作 ssh服务器的安装 farsight@ubuntu:~$ sudo apt-get install openssh-server ...