指令和数据绑定到内存地址的条件
- 编译时— 若知道进程在内存里的驻留地址,直接生成 绝对代码
- 加载时— 若不知道进程的驻留地址,那么生成可重定位代码
- 执行时— 如果进程需要进行内存段之间的移动,那么需要延迟到执行时才进行
逻辑地址空间和物理地址空间
CPU 所生成的地址通常称为逻辑地址( logical address) ,而内存单元所看到的地址(I!IJ
加载到内存地址寄存器(memory-address register) 中的地址)通常称为物理地址(physical
address) 。
编译和加载时的地址绑定方法生成相同的逻辑地址和物理地址。但是, 执行时的地址
绑定方案导致不同的逻辑地址和物理地址。对于这种情况, 通常称逻辑地址为虚拟地址
(virtual address)。在本书中, 对逻辑地址和虚拟地址不作区分。由程序所生成的所有逻辑
地址的集合称为逻辑地址空间(logical address space), 与这些逻辑地址相对应的所有物理
地址的集合称为物理地址空间(physical address space)。因此, 对千执行时地址绑定方案,
逻辑地址空间与物理地址空间是不同的。
运行时从虚拟地址到物理地址的映射是由被称为内存管理单元(memory-management
unit, MMU)的硬件设备来完成的。
动态链接
动态链接的概念与动态加载相似。只是这里不是将加载延迟到运行时,而
是将链接延迟到运行时
动态加载
迄今为止所讨论的是一个进程的整个程序和数据必须处于物理内存中,以便执行。因
此进程的大小受物理内存大小的限制。为了获得更好的内存空间使用率,可以使用动态加
载(dynamic loading) 。采用动态加载时,一个子程序只有在调用时才被加载。所有子程序
都以可重定位的形式保存在磁盘上。主程序装入内存并执行。当一个子程序需要调用另一
个子程序时,调用子程序首先检查另一个子程序是否己加载。如果没有,可重定位的链接
程序将用来加载所需要的子程序,并更新程序的地址表以反映这→变化。接着,控制传递
给新加载的子程序。
动态加载的优点是不用的子程序决不会被加载。如果大多数代码需要用来处理异常情
况,如错误处理,那么这种方法特别有用。对于这种情况,虽然总体上程序比较大,但是
所使用的部分(即加载的部分)可能小很多。
动态加载不需要操作系统提供特别的支持。利用这种方法来设计程序主要是用户的责
任。不过,操作系统可以帮助程序员,如提供子程序库以实现动态加载。
交换
进程需要在内存中以便执行。不过,进程可以暂时从内存中交换(swap) 到备份存储
(backing store) 上,当需要再次执行时再调回到内存中。(例子:轮转法CPU调度)
如何进程换出roll out进程换入 roll in,操作系统较少采用。
连续内存分配
内存通常分为两个区域:一个用于驻留操作系统,另一个用于用户进程。操作系统可
以位于低内存,也可位于高内存。影响这一决定的主要因素是中断向量的位置。由于中断
向量通常位于低内存,因此程序员通常将操作系统也放在低内存。在本书中,只讨论操作
系统位于低内存的情况。真他情况的讨论类似。
通常需要将多个进程同时放在内存中,因此需要考虑如何为输入队列中需要调入内存
的进程分配内存空间。采用连续内存分配( contiguous memo可allocation) 时,每个进程位
于一个连续的内存区域。
内存映射与保护问题
通过采用重定位寄存器(已在8.1.3 小节讨论)和界限地址寄存器(己在8. 1.1小节讨论),可以实现这种保护。重定位寄存器含有最小的物理地址值;界限地址寄存器含有逻辑地址的范围值(例如,重定位=100040 ,界限=74600) 。有了重定位寄存器和界限地址寄存器,每个逻辑地址必须小于界限地址寄存器。MMU 动’;ti:ltfp将逻辑地址加上重定位寄存器的值后映射成物理地址。映射后的物理地址再送交内存单元
内存分配方法
最为简单的内存分配方法之一就是将内存分为多个固定大小的分区(partition) 。每个分区只能容纳一个进程。因此,多道程序的程度会受分区数所限制。如果使用这种多分区方法(multiple-partition method) ,当一个分区空闲时,可以从输入队列中选择一个进程,以调入到空闲分区。当进程终止时,其分区可以被其他进程所使用。
这种方法最初为IBM 08/360 操作系统(称为MFT) 所使用,现在已不再使用。下面所描
述的方法是固定分区方案的推广(称为MV凹,它主要用于批处理环境。这里所描述的许
多思想也可用于采用纯分段内存管理的分时操作系统。
在可变分区(variable-partition) 方案里,操作系统有一个表,用于记录哪些内存可用
和哪些内存已被占用。-开始,所有内存都可用于用户进程,因此可以作为一大块可用内
存,称为孔(hole) 。当有新进程需要内存时,为该进程查找足够大的孔。如果找到,可以
从该孔为该进程分配所需的内存,孔内未分配的内存可以下次再用。
随着进程进入系统,它们将被加入到输入队列。操作系统根据所有进程的内存需要和
现有可用内存情况来决定哪些进程可分配内存。当进程分配到空间时,它就装入内存,并
开始竞争CPU 。当进程终It时,它将释放内存,该内存可以被操作系统分配给输入队列中
的其他进程。
在任意时候,再→组可用孔(块)大小列表和输入队列。操作系统根据调度算法来对
输入队列进行排序。内存不断地分配给进程,直到下-个进程的内存需求不能满足为止,
这时没有足够大的可用孔来装入进程。操作系统可以等到有足够大的空间,或者往下扫描
输入队列以确定是否有其他内存需求较小的进程可以被满足。
通常,→组不同大小的孔分散在内存中。当新进程需要内存时,系统为该进程查找足
够大的孔。如果孔太大,那么就分为两块:一块分配给新进程,另一块还回到孔集合。当
进程终止时,它将释放其内存,该内存将还给孔集合。如果新孔与其他孔相邻,那么将这
些孔合并成大孔。这时,系统可以检查是否杳进程在等待内存~间,新合井的内存空间是
否满足等待进程。
这种方法是通用动态存储分配问题的二种情况(根据一组空闲孔来分配大小为n 的请
求)。这个问题有许多解决方法。从-组可用孔中选择-个空闲孔的最为常用方法有首次适
应( first岳1)、最佳适应(best-fiO 、最差适应(worst-fit) 。
·首次适应:分配第一小足够大的孔。查找可以从头开始,也可以从上次首次适应结束时开始(避开碎片)。一旦找到足够大的空闲孔,就可以停止。
·最佳适应:分配最小的足够大的孔。必须查找整个列表,除非列表按大小排序。这
种方法可以产生最小剩余孔。
·最差适应:分配最大孔。同样,必须查找整个列表,除非列表按大小排序。这种
方法可以产生最大剩余孔,该孔可能比最佳适应方法产生的较小剩余孔更为有用。
模拟结果显示首次适应和最佳适应方法在执行时间和利用空间方面都好于最差适应
方法。首次适应和最佳适应方法在利用空间方面难分伯仲,但是首次适应方法要更快些。
碎片
首次适应方法和最佳适应方法算法都有外部碎片问题(external 企agmentation) 0 随着
进程装入和移出内存,空闲内存空间被分为小片段。当所有总的可用内存之和可以满足请
求,但并不连续时,这就出现了外部碎片问题,该问题可能很严重。在最坏情况下,每两
个进程之间就有空闲块(或浪费〉。如果这些内存是一整块,那么就可以再运行多个进程。