第7章 运行时环境
运行时环境负责管理目标计算机的寄存器和存储器,为程序执行提供内存分配、变量访问和过程调用机制。
7.1 程序执行时的存储器组织
存储器布局
程序运行时,存储器通常分为代码段、静态数据区、栈区和堆区。
三种运行时环境
| 类型 | 特点 | 典型语言 | 分配方式 |
|---|---|---|---|
| 完全静态 | 无递归、无动态分配、无指针 | FORTRAN 77 | 全部预分配 |
| 基于栈 | 递归、局部变量动态分配 | C、Pascal、Ada | 栈式分配活动记录 |
| 完全动态 | 自动内存管理、垃圾回收 | LISP、Smalltalk | 堆分配为主 |
7.2 完全静态运行时环境
特点
- 所有变量(全局和局部)均为静态分配
- 每个过程只有一个活动记录,执行前分配
- 通过固定地址直接访问所有变量
调用序列
调用者:
1. 计算自变量 → 保存到被调用过程的参数位置
2. 保存返回地址
3. 跳转到被调用过程
被调用者:
1. 执行代码
2. 将返回值放入指定位置
3. 跳转回返回地址
7.3 基于栈的运行时环境
活动记录(Activation Record / Stack Frame)
活动记录典型布局:
┌──────────────┐
│ 实参(参数) │
├──────────────┤
│ 返回值地址 │
├──────────────┤
│ 控制链(old FP)│ ← 帧指针 fp
├──────────────┤
│ 访问链 │
├──────────────┤
│ 保存的寄存器 │
├──────────────┤
│ 局部变量 │
├──────────────┤
│ 临时变量 │
└──────────────┘
← 栈指针 sp
调用序列(Calling Sequence)
调用者:
1. 计算实参并压入栈
2. 将返回地址压入栈
3. 跳转到被调用过程
被调用者:
1. 保存旧 fp(控制链)
2. 将 sp 复制到 fp(建立新的帧指针)
3. 增加 sp(为局部变量和临时变量分配空间)
4. 保存需要的寄存器
5. 执行过程体
6. 恢复寄存器
7. 恢复 fp 和 sp
8. 跳转到返回地址
嵌套过程和访问链(Access Link)
- 问题:嵌套过程如何访问外层过程的变量?
- 解决方案:
- 访问链(静态链):每个活动记录中保存指向直接外层活动记录的指针
- Display 表:从栈外数组保存每层嵌套的最新活动记录指针
- 访问链的长度 = 嵌套深度差
7.4 动态存储
堆(Heap)分配
- 用于动态创建的数据结构(链表、树、对象等)
- 手动管理:
malloc/free(C)、new/delete(C++) - 自动管理:垃圾回收
垃圾回收(Garbage Collection)
标记-清扫(Mark-and-Sweep)
第1遍(标记):从根集出发,标记所有可达对象
第2遍(清扫):遍历堆,回收所有未标记的对象
引用计数(Reference Counting)
- 每个对象维护引用计数
- 计数归零时立即回收
- 缺点:无法处理循环引用
停止-复制(Stop-and-Copy)
- 将堆分成两半
- 只使用一半,满了后将存活对象复制到另一半
- 自动压缩内存(消除碎片)
7.5 参数传递机制
| 机制 | 含义 | 典型语言 |
|---|---|---|
| 传值(call by value) | 传递实参的值(副本) | C(默认)、Pascal(val) |
| 传引用(call by reference) | 传递实参的地址 | C++(&)、Pascal(var) |
| 传结果(call by result) | 返回时复制值到实参 | Ada(out) |
| 传值-结果(call by value-result) | 进入时复制值,返回时复制回 | Ada(in out) |
| 传名(call by name) | 文本替换(thunk) | Algol 60 |
传值 vs 传引用对比
void swap_val(int x, int y) {
int t = x; x = y; y = t; // 不影响实参
}
void swap_ref(int &x, int &y) {
int t = x; x = y; y = t; // 交换实参
}
7.6 TINY 语言的运行时环境
- TINY 无递归、无嵌套过程 → 可用完全静态环境
- 但 TM 机使用基于栈的环境(为 C-Minus 准备)
- TINY 环境简单:变量固定位置、无活动记录管理
考试重点
★★★ 第一梯队
| 考点 | 典型题型 |
|---|---|
| 活动记录的布局图 | 标出各字段(参数、控制链、返回地址、局部变量等) |
★★☆ 第二梯队
| 考点 | 典型题型 |
|---|---|
| 三种运行时环境的对比 | 静态 vs 栈式 vs 动态 |
| 调用序列 | 调用者和被调用者的职责划分 |
| 访问链 | 嵌套过程中的变量访问路径 |
| 参数传递机制 | 传值 vs 传引用经典对比题 |
| 垃圾回收的标记-清扫算法 | 算法步骤 |
★☆☆ 第三梯队
| 考点 | 典型题型 |
|---|---|
| 引用计数 vs 停止-复制 | 对比 |
| TINY 运行时环境 | 简答 |