四 存储器管理
建议配合学校 PPT 看,没有图片,有些地方没图可能不太好理解
4.1 存储器的层次结构
寄存器 ⏟ C P U 寄存器 、 高速缓存、主存、磁盘缓存 ⏟ 主存 、 磁盘、可移动存储介质 ⏟ 辅存 → 速度:高 → 低 → 容量:小 → 大 → 价格:高 → 低 \underbrace{寄存器}_{CPU寄存器}、\underbrace{高速缓存、主存、磁盘缓存}_{主存}、\underbrace{磁盘、可移动存储介质}_{辅存} \\ \xrightarrow[]{速度:高\rarr 低} \\ \xrightarrow[]{容量:小\rarr 大} \\ \xrightarrow[]{价格:高\rarr 低} \\ CPU寄存器 寄存器、主存 高速缓存、主存、磁盘缓存、辅存 磁盘、可移动存储介质速度:高→低容量:小→大价格:高→低
4.1.1 存储器的层次结构
4.1.2 存储器管理的目的和功能
主存储器的分配和管理:按用户要求把适当的存储空间分配给相应的作业。
其应当具有的功能:
- 记住每个存储区域的状态
- 实施分配
- 接收系统或用户释放的存储区域
提高主存储器的利用率:使多道程序能动态地共享主存。
“扩充”主存容量:借助于提供虚拟存储器或其它自动覆盖技术来达到,即为用户提供比主存还大的地址空间。
存储保护:确保务道用户作业都在所分配的存储区内操作,互不干扰。
4.1.3 存储分配的三种方式
存储分配的目的:解决多道作业之间共享主存的问题。
三种方式:
- 直接指定方式:现在几乎没有 OS 在用。
- 静态分配方式:程序进行装入时确定其在主存中的相应位置并分配其需要的全部存储量。程序执行过程中,到退出前,不允许再申请存储量,不允许“搬家”。
- 动态分配方式:程序进行装入时确定其在主存中的相应位置,但执行过程中可根据需要申请附加的存储空间。程序执行时,若有部分空间不需要可以归还给操作系统。存储区域大小可变,允许搬家。
4.2 程序的装入和链接
操作系统对用户程序的处理步骤:
源程序
→
编译程序
↓
私有源语句库、系统源语句库
→
目标模块
→
链接程序
↓
私有目标库、系统目标库
→
装入模块
→
装入程序
→
进入内存
源程序\rarr \overset{\overset{私有源语句库、系统源语句库}{\darr}}{编译程序} \rarr 目标模块 \rarr \overset{\overset{私有目标库、系统目标库}{\darr}}{链接程序} \rarr 装入模块 \rarr 装入程序 \rarr 进入内存
源程序→编译程序↓私有源语句库、系统源语句库→目标模块→链接程序↓私有目标库、系统目标库→装入模块→装入程序→进入内存
4.2.1 程序的装入
根据存储空间的分配方式,将一个装入模块装入内存时,可采用三种方式:
- 绝对装入方式:根据程序直接装到某个存储地址。
- 可重定位装入方式:
- 重定位:目标模块中的为相对地址,相对地址修改为绝对地址的过程即为重定位。
- 可分为两种方式:
- 静态重定位:地址变换在装入内存时一次完成。
- 动态重定位:把地址转换推迟到程序执行时,随着对每条指令或数据的访问而进行。
4.2.2 程序的链接
程序的链接:将经过编译后所得到的一组目标模块以及它们所需要的库函数,装配成一个完整的装入模块。
根据链接时间的不同,可分为三种方式:
- 静态链接:程序运行前,就将目标模块及它们所需的库函数链接成一个完整的装入模块。
- 装入时动态链接:装入一个目标模块时,若发生一个外部模块调用,将引起装入程序去找出相应的外部目标模块,并将其装入内存。
- 运行时动态链接:将某些目标模块的链接推迟到执行时才进行,即在执行过程中,若发现一个被调用模块尚未装入内存时,由 OS 去找到该模块,将它装入内存,并链接到调用模块上。
4.3 连续分配存储管理方式
连续分配:为用户程序分配一个连续的内存空间。
内零头:分配给用户但用户没有使用的空间,即“多分配的空间”。
外零头:没有分配但因为太小而无法分配的空间,即“分不出去的空间”。
有三种分配方式:单一连续分配方式、分区式分配方式、可重定位分区分配。
4.3.1 单一连续分配
- 内存中仅驻留一道用户程序,整个用户区为一个用户独占。
- 内存分为系统区与用户区两个区域。应用程序装入用户区后,可使用用户区全部空间。
4.3.2 固定分区分配
- 分配思想:将内存用户空间划分为若干个固定大小的区域,每个区域称为一个分区,在每个分区中只装入一道作业 ,从而支持多道程序并发设计。
- 用户作业装入及运行过程中,区域的大小与边界不能改变。
- 每个分区的大小可以相等,也可以不等。
- 系统会建立一张分区说明表,用于标记每个分区的分区号、大小、起址、分配状态等信息。
- 分配过程:当有作业要装入内存时,内存分配程序检索分区说明表,从中找出一个尚未使用的满足大小要求的分区分配给该作业,然后修改分区的状态;如果找不到合适的分区,就拒绝为该作业分配内存。
- 对存储空间的利用率太低,现在的操作系统几乎不使用。
4.3.3 动态分区分配
- 指根据进程的实际需要,动态地为之分配连续的内存空间。
- 它的产生是为了提高主存的使用率。
- 有两种方案,一种是分区数目固定、大小可变,一种是分区数目大小均可变。
- 实现时需要解决的问题:
- 分配时的数据结构:空闲分区表或空闲分区链。
- 分配算法:
- 基于顺序搜索:
- 最佳适应算法:总寻找其大小最接近作业要求的存储区域。
- 最坏适应算法:总寻找最大的空白区。
- 首次适应算法:按地址递增顺序查找,找到第一个可以分配的存储区域就分配。
- 下次适应算法:按首次适应算法的方式,但每次查找都从上次查找结束的地方开始查找,查到尾部边界时可以回到头部继续查找,直到开始查找的地方。
- 基于索引搜索:
- 快速适应算法:
- 将空闲分区根据其容量大小进行分类,对于每一类具有相同容量的所有空闲分区,单独设立一个空闲分区链表。同时,在内存中设立一张管理分区类型,并记录了该类型空闲分区链表表头的索引表,该表的每一个表项记录了对应类型空闲分区链表表头的指针。
- 分配过程:根据进程的长度,寻找到能容纳它的最小空闲分区链表,并取下第一块进行分配即可。
- 伙伴系统
- 快速适应算法:
- 基于顺序搜索:
- 内存分配操作:主要涉及分配内存与回收内存操作。
4.3.4 哈希算法
- 利用哈希快速查找的优点,以及空闲分区在可利用空间表中的分布规律,建立哈希函数,构造一
张哈希表,以空闲分区大小为关键字,每一个表项记录了一个对应的空闲分区链表表头指针。 - 当进行空闲分区分配时,根据所需空闲分区大小,通过哈希函数计算,即得到在哈希表中的位置,
从中得到相应的空闲分区链表,实现最佳分配策略。
4.3.5 可重定位分区分配
4.3.5.1 紧凑
- 可变式分区分配策略消除了内零头,但不可避免地会出现外零头。
- 为了利用这些外零头,有一个直观的方法,就是将现在内存中分散的外零头拼接为一个大分区。
- 这个方法有一个实现思路,就是将内存中现有的作业进行移动,使它们全部相邻接。这种技术即为存储器的紧凑。
4.3.5.2 动态重定位
- 存储器的紧凑需要移动内存中现有的作业,而移动作业需要调整作业中的一些地址信息。一个较可靠的方法即为采用动态重定位技术。
- 动态重定位的中心思想是:程序运行时要访问的内存地址,由相对地址与重定位寄存器中的地址共同决定。作业需要移动时,无需改动程序的相对地址,只要改变重定位寄存器中的地址即可。
4.4 基本分页存储管理方式
离散分配存储管理方式出现原因:解决连续分配存储管理方式的碎片。虽然紧凑技术也可以解决,但代价较高。而如果允许作业/进程离散放入不邻接的分区中,就可以避免拼接。
离散分配方式:分布式、分段式、段页式。
4.4.1 分页存储管理基本思想
空间划分:
- 页:将一个用户进程的地址空间逻辑地划分为若干个大小相等的区域,即为页,各页从0开始编号。
- 块:内存空间也分成若干个与页大小相等的区域,即为块,也从0开始编号。
优点:
- 没有外零头
- 仅有小于一个页面的内零头
实现时需要解决的两个基本问题:
- 如何建立程序空间与主存空间的映射
- 如何进行地址变换
纯分页存储管理方式:
- 将每个作业全部装入内存后方能运行
- 不具有支持实现虚拟存储器的功能
- 有一次性和驻留性的特征
实现时需要的数据结构:
- 页表:每个进程对应一个页表,描述该进程的各页面在内存中对应的物理块号。
- 实现从页号到物理块号的地址映射。
- 其基址及长度由页表寄存器给出。
- 访问一个数据/指令时,需要访问内存两次(页表一次,内存一次)。
- 作业表:整个系统有一张,记录作业的页表情况,包含进程号、页表长度、页表始址等信息。
- 空闲块表:整个系统有一张,记录主存当前空闲块。
地址结构:
- 逻辑地址可转变为:页号+页内位移量。
- 页号、位移量的划分是由操作系统完成的,对用户透明。
4.4.2 地址变换机构
功能:将用户的逻辑地址转变为内存中的物理地址。
由于页的大小和内存物理块的大小相同,所以页内位移量即为物理块内位移量。因此地址转变的关键就变成了页号到物理块号的转换,这部分由页表完成。
基本的地址变换机构:
- 使用寄存器存放页表:速度快,但成本高,且对于规模较大的系统,页表会很长,只用寄存器放不下。
- 一般系统将页表存储在内存中。
具有快表的地址变换机构:
- 将进程最近访问过的一组页表放在 Cache 中,这样可以大大提高访问页表的速度。
- 这组在 Cache 中的页表即为快表。
4.4.3 访问内存的有效时间 EAT
定义:从进程发出指定逻辑地址的访问请求,经过地址变换,再到内存中找到对应的物理单元并取出数据,所花费的总时间。
访问内存时间的计算方式:如果查找的页在快表中有存储信息,那么这次查找时间为 检索快表时间+访问内存时间
,记为
t
1
t_1
t1。如果在快表中没有,则这次查找时间为 检索快表时间+2*访问内存时间
,记为
t
2
t_2
t2。
访问内存的有效时间的计算方式:记快表命中率为 h h h,那么有效时间的计算公式即为 h ⋅ t 1 + ( 1 − h ) ⋅ t 2 h\sdot t_1+(1-h)\sdot t_2 h⋅t1+(1−h)⋅t2。
4.4.4 两级和多级页表
两级页表的出现原因:当地址空间较大时,页面会增多,页表也会变长。当页表长到无法保存在一个连续区中,仅一级页表已经无法满足需求。
上述问题的一个解决思路即为:将页表进行分页,并离散地将各个页面存放在不同的物理块中。再为离散的页表建立一张页表(称为外层页表),在每个页表项中记录页表分页的物理块号。
当内存再大些时,二级页表可能也无法满足需求,这时就需要引入更多级的页表。如对 64 位的机器,采用的是多级(4 级以上)页表结构。
4.4.5 反置页表 IPT
IPT 的出现原因:对大地址空间系统(64 位系统就是一个很现实的例子),多级页表使用起来十分繁琐。同时,由于逻辑地址空间的增长速度快于物理地址空间,页表的占用空间也会越来越大。为了解决大页表占用内存过多的情况,需要避免一个进程一个页表。
以上方法的一种解决思路:不让页表与逻辑地址空间的大小相对应,而让页表与物理地址空间的大小相对应。
IPT 思想:
- IPT 是为主存中的每个物理块建立一个页表项建立一个页表项并按照块号排序。
- 该表每个表项包含正在访问该物理块的进程标识、页号及特征位,用来完成主存物理块到访问进程的页号的转换。
使用 IPT 进行地址转换的过程:
- 给出进程标识和页号,用它们去比较 IPT。
- 若整个反置页表中未能找到匹配的页表项,说明该页不在主存,产生请求调页中断,请求操作系统调入。
- 否则,该表项的序号便是物理块号。块号加上位移,便形成物理地址。
4.4.6 对换
定义:指把内存中暂不能运行的进程或暂时不用和程序和数据,换到外存上,以腾出足够的内存空间,把已具备运行条件的进程,或进程所需要的程序和数据,换入内存。
实现:可在系统中设一对换进程,以执行换进内存、换出到外存操作。
分类:
- 整体对换(进程对换):以整个进程为单位
- 页面对换/分段对换:对换以页或段为单位进行部分对换,它是实现请求分页及请求分段存储器的基础,支持虚存系统。
实现需要的功能:
- 对换空间的管理
- 进程的换出
- 进程的换入
对换空间的管理:
- 外存被分为文件区与对换区两部分。
- 文件区用于存放文件,管理时重在提高空间利用率,所以采用离散分配方式。
- 对换区用于存放从内存换出的进程,管理时重在提高换入换出速度,所以采用连续分配方式。
进程的换出:
- 选择:首先选择阻塞或睡眠状态的进程,若有多个,按优先级由低到高进行选择。若没有此状态进程,则选择就绪状态的,仍然按优先级由低到高进行选择。还应考虑进程在内存中的驻留时间,优先选择驻留时间长的进程。
进程的换入:
- 从 PCB 集合中查找“就绪且换出”的进程,若有多个,则选择换出时间最长的。
- 根据进程大小申请内存,成功则读入,否则要先执行换出,再换入。
- 还有可换入进程,则转向1。直至无“就绪且换出”进程或无法获得足够内存空间为止。
4.5 基本分段存储管理方式
4.5.1 分段式存储管理方式的引入
主要是出于以下考量:
- 方便编程
- 依据程序的模块化设计思想。
- 分段共享
- 一般实现程序和数据共享时都是以信息的逻辑单位(过程、函数或文件)为基础的。
- 在分页系统中的每一页都只是存放信息的物理单位,其本身并无完整意义,因而不便于实现信息共享。
- 段是信息的逻辑单位,可以为共享过程建立一个独立的段,更便于实现程序和数据的共享。
- 分段保护
- 对内存中的信息的保护,同样也是对信息的逻辑单位进行保护。采用分段存储管理,对实现保护更有效和方便。
- 动态链接
- 程序运行时,先将主程序所对应的目标程序装入内存并启动运行,当运行过程中又需要调用某段时,才将该段调入内存并进行链接。
- 动态增长
- 分段存储管理可以较好地解决程序运行中无法预知的数据段增大问题。
4.5.2 分段系统的基本原理
分段:
- 作业地址空间按逻辑信息的完整性被划分为若干个段
- 每段有段名(或段号),每段从0开始编址
- 段内的地址空间是连续的
实现关键:如何保证分段(二维)地址空间中的一个作业在线性(一维)的存储空间中正确运行。可以采用和分布管理一样的动态重定位技术。
段表:
- 应像分页系统那样,在系统中为每个进程建立一张段映射表,简称“段表”。每个段在表中占有一个表项,其中记录了该段在内存中的起始地址和段的长度。
- 通常将段表放在内存中,执行中的进程可通过查找段表找到每个段所对应的内存区。
- 作用:实现从逻辑段到物理内存区的映射。
地址变换机构:使用段表寄存器。
地址变换过程:
- 根据段表寄存器的内容找到该作业的段表地址;
- 利用有效地址中的段号作为检索段表的索引,得到该段在主存的起始地址;
- 将段的主存起始地址和位移量相加,即得访问主存的物理地址。
段表放在内存中时,与分页管理方式相似,每访问一个数据需要访问内存两次。因此,也可以设置快表,以提高访问速度。
4.5.3 信息共享
分段易于实现段的共享与保护。
对分页存储管理方式:
- 数据页面共享:实现起来比较简单。因为这个数据页面可以安排在诸作业地址空间中的任何一个页面上。
- 代码页面共享:必须把共享的代码安排到所有共享它的作业地址空间中相同页号的页面中。即共享代码所在的地址空间必须重叠。(因为作业在运行前需要链接,而链接后,其所占页号就确定了。)
对分段存储管理方式:
- 实现方式十分容易,将两个作业段表的相应表目都指向 COS 过程的同一物理副本即可。
4.5.4 段页式存储管理方式
分页管理的特点:
- 管理效率高
- 没有外零头
- 内零头小
分段管理的特点:
- 符合模块化思想
- 每个分段都具备完整的功能
- 方便代码共享、保护
- 没有内零头,存在外零头
二者长处结合就可以得到段页式存储管理方式。
原理:分段与分页相结合。先将用户程序分段,段内再划分为若干页。每个段有段名(段号),每段内部的页有连续的页号。
内存划分:按页式存储管理方案。
内存分配:以页为单位进行离散分配。
逻辑地址结构:由段号、段内页号、段内地址构成。
地址变换过程:
- 从段表寄存器从获得进程段表的起始地址,根据该地址,查找进程的段表。
- 然后,根据逻辑地址指定的段号检索段表,找到对应段的页表起始地址。
- 再根据逻辑地址中指定的页号检索该页表,找到对应页所在的物理块号。
- 最后,用物理块号加上逻辑地址中指定的页内偏移量,形成物理地址。
访问内存过程:三次,一次段表,一次页表,一次数据。因此,访问速度可以预见地低。
评价:
- 综合了分页与分段的好处。
- 但硬件成本、系统复杂度与管理开销大大增加。
- 适合大、中型计算机系统,不太适合小、微型计算机系统。
4.6 虚拟存储器的基本概念
虚拟存储器的出现原因:
- 出现了需求存储容量超过整个内存空间的程序
- 有大量作业需要装入内存造成内存不足
上述问题的解决方案中,除了物理上增加内存容量这种需要增加成本且只能有限增加的方法,还可以逻辑上增加内存容量,于是虚拟存储器出现了。
4.6.1 虚拟存储器的引入
常规存储器管理方式的特征:
- 一次性:必须将一个作业全部装入内存才能运行。这限制了大作业的运行和作业并发执行的程度。
- 驻留性:作业装入后一直驻留内存直到作业完成。内存中难免会存在无用或暂时不用的程序或数据,造成内存的浪费。
内存的逻辑扩充方法:
- 覆盖:应用程序手动把需要的的指令和数据保存在内存中,解决了“一次性”问题。
- 对换:操作系统自动将暂时不能执行的程序保存到外存中,解决了“驻留性”问题。
- 虚拟存储:在有限容量的内存中,自动装入更多更大的程序。
4.6.2 局部性原理
程序执行的局部性原理:程序的执行总是呈现局部性。即在一个较短的时间段内,程序的执行仅限于某个部分;相应的,它所访问的存储空间也局限于某个区域。因此,只要保证进程执行所需的部分程序和数据驻留在内存,一段时间内进程都能顺利执行。
程序的局限性表现在两个方面:
- 时间局限性:如果程序中的某条指令一旦执行,则不久以后该指令可能再次执行;如果某数据被访问过, 则不久以后该数据可能再次被访问。其产生的典型原因,是由于在程序中存在着大量的循环操作。
- 空间局限性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问。程序在一段时间内所访问的地址,可能集中在一定的范围之内,其典型情况便是程序的顺序执行。
4.6.3 虚拟存储器的定义
虚拟存储器的基本工作情况:
- 基于局部性原理。一个作业运行前,仅将那些当前要运行的页面(段)装入内存启动运行,其余暂在外存。
- 若运行所需页面(段)不在内存,则利用请求调页(段)功能将其调入内存。
- 若此时内存满,则利用置换功能,将内存中暂时不用的部分页面(段)调至外存,再将所需页面(段)调入。
- 这样,可实现大程序在小内存中运行,也可实现内存中同时装入更多的进程并发执行。
虚拟存储器的定义:是指具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统。
在有虚拟存储器的情况下,整个存储系统的逻辑容量由内存容量与外存容量之和决定。虚拟存储器的运行速度接近于内存速度,但成本又接近于外存。
虚拟存储器实现时需要解决的问题:
- 主存辅存统一管理问题
- 逻辑地址到物理地址的转换问题
- 部分装入和部分对换问题
虚拟存储管理的实现技术:
- 请求分页存储管理
- 在纯分页系统的基础上,增加了请求调页、页面置换两大功能。
- 为增加以上两个重要功能,系统需要提供的硬件支持有:
- 请求分页的页表机制
- 缺页中断机构
- 地址变换机构
- 还需要 OS 提供对应软件支持
- 请求分段存储管理
- 在纯分段系统的基础上,增加了请求调段、分段置换两大功能。
- 为增加以上两个重要功能,系统需要提供的硬件支持有:
- 请求分段的页表机制
- 缺段中断机构
- 地址变换机构
- 还需要 OS 提供对应软件支持
- 请求段页式存储管理
- 在段页式系统基础上,增加了请求调页、页面置换两大功能。
4.6.4 虚拟存储器的特征
- 多次性:指一个作业被分成多次调入内存运行。
- 对换性:指作业的运行过程中进行换进、换出,有效提高了内存利用率。
- 虚拟性:指能从逻辑上扩充内存容量,使用户所看到的内存容量远大于实际内存容量。
4.7 请求分页存储管理方式
工作原理:作业运行时,只将当前的一部分装入内存,其余的放在辅存,一旦发现访问的页不在主存中,则发出缺页中断,由 OS 将其从辅存调入主存,如果内存无空块,则根据某种算法选择一个页淘汰以便装入新的页面。
为实现请求调页、页面置换两大功能,系统需要提供的硬件支持有:
- 请求分页的页表机制
- 缺页中断机构
- 地址变换机构
4.7.1 请求分页中的硬件支持
页表机制:
-
页表的页描述子增加了四个信息标识位,其结构如下:
页号 页框号Q 状态位D 访问位A 修改位M 外存地址 \fbox{页号} \fbox{页框号Q} \fbox{状态位D} \fbox{访问位A} \fbox{修改位M} \fbox{外存地址} 页号页框号Q状态位D访问位A修改位M外存地址- 状态位 D:说明该页是否已调入内存,D=0 时表示不在内存。
- 访问位 A:记录本页在一段时间内被访问的次数,或最近已有多久没被访问,A=0 时表示该页未被访问。
- 修改位 M:表示该页在调入内存后是否被修改过,M=0 时表示该页在内存中未被修改。
- 外存地址:指出该页在外存上的地址。
缺页中断机构:
- 与一般中断相比,缺页中断比较特殊,主要表现为:
- 缺页中断在指令执行期间产生和处理中断信号,一般中断则是在指令之间接受中断。
- 一条指令可能引发多次缺页中断。
- 因此,系统中需要提供硬件寄存器或其它机构,在出现页面故障时,保存部分完成指令的状态。
- 此外,还需要使用一条特殊的返回指令,确保在出现缺页中断处恢复该指令的处理。
地址变换机构:
- 请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,再为实现虚拟存储器而增加了某些功能而形成的。
4.7.2 内存分配策略和分配算法
为进程分配物理块时,会涉及到以下问题:
- 最小物理块数的确定
- 最小物理块数:指能保证进程正常运行所需的最少物理块数。
- 它的确定与计算机的硬件结构有关,取决于指令的格式、功能和寻址方式。
- 物理块的分配策略
- 固定分配局部置换:
- 为每个进程分配一定数目的物理块,在整个运行期间不再改变。
- 困难之处在于:应为每个进程分配多少物理块难以确定。分配太少,会频繁出现缺页中断;分配太多,会使内存中驻留的进程数目减少。
- 可变分配全局置换(常用方式):
- 先为系统中的每个进程分配一定数目的物理块,OS 自身也保持一个空闲物理块队列。
- 当某进程发现缺页时,由系统从空闲物理块队列中,取出一个物理块分配给该进程,并将欲调入的(缺)页装入其中。
- 仅当空闲物理块队列中的物理块用完时,OS 才能从内存中选择一页调出,该页可能是系统中任一进程的页,这样,自然又会使那个进程的物理块减少,进而使其缺页率增加。
- 可变分配局部置换:
- 为每个进程分配一定数目的物理块,但当某进程发现缺页时,只允许从该进程在内存的页面中选出一页换出,这样就不会影响其它进程的运行。
- 在进程运行过程中统计进程的缺页率,如果缺页率高,则为其增加一定的内存页,否则适当减少其内存的页面数。
- 实现复杂,对进程缺页情况的统计需要额外的开销。
- 固定分配局部置换:
- 物理块的分配算法
- 平均分配算法:
- 将系统中所有可供分配的物理块,平均分配给各个进程。
- 表面公平,实际并不公平。因为没有考虑到各个进程本身的大小。
- 按比例分配算法:
- 根据进程大小按比例分配物理块。
- 记系统中可用的物理块总数为 m m m,每个进程的页面数为 S i S_i Si,每个进程能分到的物理块数为 b i b_i bi,则 b i = S i S ⋅ m b_i=\frac{S_i}{S} \sdot m bi=SSi⋅m。
- 考虑优先权的分配算法
- 通常的方法是将内存中可供分配的所有物理块分为两部分,一部分按比例分配给各进程,另一部分根据各进程的优先权,适当调整其份额后,分配给各进程。
- 有些系统会选择完全按优先权来为各进程分配物理块,如重要的实时控制系统。
- 平均分配算法:
4.7.3 调页策略
调页时需要解决的问题:
- 系统应当在何时把一个页面装入内存?
- 从何处调入页面?
- 页面调入过程?
- 页面置换算法?
系统应当在何时把一个页面装入内存?
- 预调页方式
- 以预测为基础的预调页策略,将那些预计在不久之后便会被访问的页面,预先调入内存。
- 若程序局部性很差,预先装入的很多页面不会很快被引用,并会占用大量的内存空间,反而降低系统的效率。
- 预调页的成功率仅约50%。
- 请求调页方式
- 仅当进程执行过程中,通过检查页表发现相应页面不在内存时,才装入该页面。
- 一次装入请求的一个页面,磁盘I/O的启动频率较高,系统的开销较大。
从何处调入页面?
- 前面说过,请求分页系统中,外存分为存放文件的文件区与存放对换页面的对换区两部分。
- 文件区通常采用离散分配方式,对换区通常采用连续分配方式。因此,对换区的 I/O 速度自然比文件区高。
- 系统应从何处将缺页调入内存,可分为三种情况:
- 对换区:系统拥有足够的对换区空间时。
- 文件区、对换区:系统缺少足够的对换区空间时,不会被修改的文件会从文件区调入。调出时,如果页面中的内容没有被修改,就不必换出;如果内容可能被修改,则需要调出到对换区,方便以后需要时再次调入。
- UNIX 方式:凡是未运行过的页面,都应从文件区调入。而对于曾经运行过但又被换出的页面,由于是被放在对换区,因此在下次调入时,应从对换区调入。
页面调入过程?
- 每当程序所要访问的页面未在内存时,便向 CPU 发出一缺页中断。
- 中断处理程序首先保留 CPU 环境,分析中断原因后,转入缺页中断处理程序。
- 如果内存已满,则须先按照某种置换算法从内存中选出一页准备换出;如果此页已被修改,则必须将它写回磁盘。
- 然后再把所缺的页调入内存,并修改页表中的相应表项,置其存在位为“1”,并将此页表项写入快表中。
- 形成所要访问数据的物理地址,再去访问内存数据。
此过程对用户透明。
缺页率
定义:程序进行期间访问页面失败次数与访问页面总次数之比。
影响因素:
- 页面大小
- 进程所分配物理块的数目
- 页面置换算法
- 程序的固有特性
4.7.4 页面置换算法
常用的页面转换算法:
- 最佳(优)置换算法
- 先进先出(FIFO)页面置换算法
- 最近最久未使用(LRU)置换算法
- Clock 置换算法
- 改进型 Clock 置换算法
- 其他置换算法
最佳置换算法
- 策略:从主存中移出永远不再需要的页面。如果没有这样的页面,则应选择最长时间不需要访问的页面。
- 理想化的算法,拥有最好的性能,但难以实现。
先进先出(FIFO)页面置换算法
- 实质:总是选择作业中驻留时间最长(即最老)的一页淘汰。
- 出发点是最早调入内存的页面不再被访问的可能性会大一些。
- 实现比较简单,对具有线性顺序访问的程序比较合适,而对其他情况效率不高。因为经常被访问的页面,往往在内存中停留最久,结果这些常用的页面却因变老而被淘汰。
- 存在一种异常现象,即在某些情况下会出现分配给的进程物理块数增多,缺页次数有时增加,有时减少的奇怪现象,这种现象称为 Belady 现象。
最近最久未使用(LRU)置换算法
-
描述:
- 基本思想是利用局部性原理,根据一个作业在执行过程中过去的页面访问踪迹来推测未来的行为。它认为过去一段时间里不曾被访问过的页面,在最近的将来可能也不会再被访问。
- 实质:当需要置换一页面时,选择在最近一段时间内最久不用的页面予以淘汰。
-
实现:周期性地对“页面访问”位进行检查,并利用它来记录一个页面自上次访问以来所经历的
时间 t t t,并选择 t t t为最大的页予以淘汰。 -
它适用于各种类型的程序,但实现起来比较困难:
- 该算法要对先前的访问历史时时加以记录和更新。
- 如果这种连续的修改完全由软件来做,系统开销太大。
- 如由硬件执行,则需要解决:
- 一个进程在内存中的各个页面各有多久未被进程访问?
- 如何快速地知道哪一页是最近最久未使用的页面?
-
由其硬件实现上的困难,可以得知其实现需要的硬件支持:
-
寄存器:记录某进程在内存中各页的使用情况。
-
需要为每个在内存中的页面配置一个移位寄存器,可表示为:
R = R n − 1 R n − 2 R n − 3 ⋯ R 2 R 1 R 0 R=R_{n-1}R_{n-2}R_{n-3} \cdots R_2R_1R_0 R=Rn−1Rn−2Rn−3⋯R2R1R0 -
当进程访问某物理块时,要将相应寄存器的最高位 R n − 1 R_{n-1} Rn−1位置成 1。系统每隔一定时间(例如 100 ms)将寄存器右移一位。
-
具有最小数值的寄存器所对应的页面,就是最近最久未使用的页面。
-
-
栈:保存当前进程使用的各个页面的页面号。
- 每当进程访问时某页面时,便将该页面号从栈中移出,压入栈顶。
- 栈底则是最近最久未使用页面的页面号。
-
最少使用(LFU)置换算法
- 基本方法:记录每个页面的访问次数,最少访问的页面首先考虑淘汰。
- 实际采取方法:为页面设置移位寄存器。
Clock 置换算法
-
简单的 Clock 置换算法:
- 为每页设置一位访问位,再将内存中的所有页面都通过链接指针链接成一个循环队列。
- 当某页被访问时,其访问位被置 1。
- 置换程序从上次停止位置开始检查页面的访问位。如果是 0,就选择该页换出;若为 1,则重新将它置 0,暂不换出,相当于给该页第二次驻留内存的机会。
-
改进型 Clock 置换算法:
- 由于在内存中的页面如果在驻留期间没有被修改过,就不必将其写回辅存,那么将未修改的页面换出时的开销会小于修改过的页面。
- 于是可以改进上面的 Clock 置换算法,将换出页面的首选标准改为:
- 在最近没有被使用过
- 在驻留内存期间没有被修改过
- 于是,可以根据访问位 A 和修改位 M 组合成以下四类页面:
- 1 类:A=0,M=0,表示该页最近未被访问且未被修改,是最佳淘汰页。
- 2 类:A=0,M=1,表示该页最近未被访问但已被修改,并不是很好的淘汰页。
- 3 类:A=1,M=0,表示该页最近已被访问但未被修改,该页可能被再次访问。
- 4 类:A=1,M=1,表示该页最近已被访问且已被修改,该页极有可能被再次访问。
- 其执行过程可分为以下三步:
- 从指针所指示的当前位置开始,扫描循环队列,寻找第一类页面,将所遇到的第一个页面作为所选中的淘汰页。第一次扫描期间不改变访问位 A。
- 如果第一步失败,即查找一周后未遇到第一类页面,则开始第二轮扫描,寻找第二类页面,将所遇到的第一个这类页面作为淘汰页。在第二轮扫描期间,将所有扫描过的页面的访问位 A 都置0。
- 如果第二步也失败,亦即未找到第二类页面,则将指针返回到开始的位置,并将所有的访问位复 0。然后重复第一步,如果仍失败,必要时再重复第二步,此时一定能找到被淘汰的页。
4.8 抖动与工作集
当内存中的进程超过一定数量时,就会降入 缺页率升高->进程在等待调页完成->CPU 利用率降低->进程进一步增多->缺页率升高 的恶性循环。
4.8.1 抖动
定义:如果系统花费大量的时间把程序和数据频繁地换入和换出内存而不是执行用户指令,那么,称系统出现了抖动。
出现抖动现象时,系统显得非常繁忙,但是吞吐量很低,甚至产出为零。
产生原因:
- 进程分配的物理块太少
- 置换算法选择不当
- 全局置换使抖动传播
根本原因:选择的页面或段不恰当。
防止的根本手段:给进程分配足够多的帧。
4.8.2 工作集
工作集的出现原因:确定进程需要多少帧才能不抖动,这个确定过程需要计算。
由于程序有局部性,所以一般认为,只要分配的帧空间能覆盖整个局部就不会出现太多的缺页现象。
定义: 进程 P i 工作集合 W S i = 在最近的 Δ 时间内访问的页面集合 进程P_i工作集合WS_i=在最近的\Delta时间内访问的页面集合 进程Pi工作集合WSi=在最近的Δ时间内访问的页面集合,其中 Δ \Delta Δ为工作集窗口。
4.8.3 抖动的预防
- 采取局部置换策略
- 引入工作集的算法
- L=S准则
- L 为缺页之间的平均时间,S 为平均缺页服务时间
- 选择暂停的进程
4.9 请求分段存储管理方式
工作原理:程序运行之前,只需先调入若干个分段(不必调入所有的分段),便可启动运行。当所访问的段不在内存中时,可请求 OS 将所缺的段调入内存。
实现需要的硬件支持:
- 请求分段的段表机制
- 缺段中断机构
- 地址变换机构
4.9.1 请求分段中的硬件支持
段表机制
-
在虚拟存储系统中的所有段表,其段描述子增加五个信息标识位,结构如下:
段名 段长 段基址 存取方式 状态位P 访问位A 修改位M 增补位 外存地址 \fbox{段名} \fbox{段长} \fbox{段基址} \fbox{存取方式} \fbox{状态位P} \fbox{访问位A} \fbox{修改位M} \fbox{增补位} \fbox{外存地址} 段名段长段基址存取方式状态位P访问位A修改位M增补位外存地址- 状态位 P:说明该段是否已调入内存,P=0 时表示该段不在内存。
- 访问位 A:记录本段在一段时间内被访问的次数,A=0 时表示该段未被访问。
- 修改位 M:用于表示该段在调入内存后是否被修改过,M=0 时表示该段在内存中未被修改。
- 外存地址:用于指出该段在外存上的地址,供调入该页时使用。
- 增补位:说明该分段是否允许扩展,此外,如该段已被增补,则在写回辅存时,需另选择辅存空间。
缺段中断机构
- 状态位记录了访问段是否在内存。
- 在地址映射过程中,在段表中发现所要访问的段不在内存,则产生缺段中断。
- OS 接到此中断信号后,就调出缺段中断处理程序,根据段表中给出的外存地址,将该段调入内存,使作业继续运行下去。
- 缺段中断与缺页中断类似,主要表现为:
- 一个缺段中断要求在指令执行中间得到服务
- 一条指令可能引起多次不同的缺段中断
地址变换机构
- 过程与请求分页类似
4.9.2 分段的共享与保护
共享段表
- 为了实现分段共享,可在系统中配置一张共享段表,所有共享段都在共享段表中占有一个表项。
- 表项中有几个值得注意的属性:
- 共享进程计数 count:记录有多少进程共享该段。
- 存取控制字段:对同一共享段,不同进程有不同的操作权限。
- 段号:共享段在不同进程中有不同的段号。
共享段的分配与回收
- 共享段的分配:
- 为共享段分配内存时,对第一个请求使用该共享段的进程,由系统为该共享段分配一物理区,再把共享段调入该区,同时将该区的始址填入请求进程的段表的相应项中,还须在共享段表中增加一表项,填写有关数据,把count置为1。
- 之后,当又有其它进程需要调用该共享段时,由于该共享段已被调入内存,故此时无须再为该段分配内存,而只需在调用进程的段表中,增加一表项,填写该共享段的物理地址,在共享段表中,填上调用进程的进程名、存取控制等,再执行 ++count 操作,以表明有两个进程共享该段。
- 共享段的回收:
- 当共享此段的某进程不再需要该段时,应将该段释放,包括撤消该进程段表中共享段所对应的表项,以及执行 count-- 操作。
- 若 count 为 0,则须由系统回收该共享段的物理内存,以及取消在共享段表中该段所对应的表项,表明此时已没有进程使用该段;否则(减 1 结果不为 0),则只是取消调用者进程在共享段表中的有关记录。
分段保护
- 越界检查:
- 如果段号等于或大于段表长度,将发出地址越界中断信号。
- 这可以保证每个进程只能在自己的地址空间内运行。
- 存取控制检查:
- 环保护机构:
- 低编号的环具有高优先权。OS 核心处于 0 环内;某些重要的实用程序和操作系统服务,占居中间环;而一般的应用程序在外环上。
- 基本原则:
- 一个程序可以访问驻留在相同环或较低特权环中的数据
- 一个程序可以调用驻留在相同环或较高特权环中的服务