【操作系统】04-存储器管理

计算机操作系统——存储器管理



第四章 存储器管理

4.1 存储器的层次结构

4.1.1 多层结构的存储器系统

通用计算机存储层次至少应具有三级:最高层-CPU 寄存器、中间-主存、最底层-辅存。

较高档计算机可根据具体的功能分工细分:寄存器、高速缓存、主存储器、磁盘缓存、固定磁盘、可移动存储介质等 6 层。

在存储层次中越往上,存储介质的访问速度越快,价格也越高,相对存储容量也越小。

4.1.2 主存储器和寄存器

在计算机系统存储层次中,寄存器和主存储器又被称为可执行存储器

  1. 主存储器

    主存储器(简称内存或主存)是计算机系统中一个主要部件,用于保存进程运行时的程序和数据。

  2. 寄存器
    寄存器具有与处理机相同的速度,访问速度最快,完全能与 CPU 协调工作。寄存器的长度一般以字(word)为单位。

4.1.3 高速缓存和磁盘缓存

1、高速缓存

高速缓存其容量大于或远大于寄存器,访问速度快于主存储器。

根据程序执行的局部性原理(即程序在执行时将呈现出局部性规律,在一较短的时间内,程序的执行仅局限于某个部分),将主存中一些经常访问的信息存放在高速缓存中,减少访问主存储器的次数,可大幅度提高程序执行速度。

2、磁盘缓存

磁盘缓存本身并不是一种实际存在的存储介质,它依托于固定磁盘,提供对主存储器存储空间的扩充,即利用主存中的存储空间,来暂存从磁盘中读出(或写入)的信息。

由于目前磁盘的 I/O 速度远低于对主存的访问速度,因此将频繁使用的一部分磁盘数据和信息,暂时存放在磁盘缓存中,可减少访问磁盘的次数


4.2 程序的装入和链接

对用户程序的处理步骤:

  1. 编译:由编译程序(Compiler)将用户源代码编译成若干个目标模块(Object Module);
  2. 链接:由链接程序(Linker)将编译后形成的一组目标模块,以及它们所需要的库函数链接在一起,形成一个完整的装入模块(Load Module);
  3. 装入:由装入程序(Loader)将装入模块装入内存。

4.2.1 程序的装入

将一个装入模块装入内存有三种方式:绝对装入方式可重定位装入方式动态运行时装入方式

  1. 绝对装入方式(Absolute Loading Mode)

    如果知道程序将驻留在内存的什么位置,那么编译程序将产生绝对地址的目标代码。绝对装入程序按照装入模块中的地址,将程序和数据装入内存。程序中的逻辑地址与实际内存地址完全相同。

    绝对装入方式只能将目标模块装入到内存中事先指定的位置,只适用于单道程序环境

  2. 可重定位装入方式(Relocation Loading Mode)

    多道程序环境下,可采用可重定位装入方式。根据内存的当前情况,将装入模块装入到内存的适当位置。装入模块中的所有逻辑地址与实际装入内存的物理地址不同。

    通常把在装入时对目标程序中指令和数据的修改过程称为重定位。又因为地址变换通常是在装入时一次完成的,以后不再改变,故称为静态重定位

  3. 动态运行时装入方式(Dynamic Run-time Loading)

    可重定位装入方式可将装入模块装入到内存中任何允许的位置,但不允许程序运行时在内存中移动位置。在运行过程中它在内存中的位置需要改变,采用动态运行时装入方式。

    动态运行时的装入程序在把装入模块装入内存后,并不立即把装入模块中的相对地址转换为绝对地址,而是把这种地址转换推迟到程序真正要执行时才进行。装入内存后的所有地址都仍是相对地址。

    为使地址转换不影响指令的执行速度,这种方式需要一个重定位寄存器的支持

4.2.2 程序的链接

根据链接时间的不同,可把链接分成如下三种:

  1. 静态链接(Static Linking)

    在程序运行之前,先将各目标模块及它们所需的库函数,链接成一个完整的装配模块,以后不再拆开。这种事先进行链接的方式称为静态链接方式。

  2. 装入时动态链接(Load-time Dynamic Linking)

    这是指将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的链接方式。

  3. 运行时动态链接(Run-time Dynamic Linking)

    这是指对某些目标模块的链接,是在程序执行中需要该(目标)模 块时,才对它进行的链接。


4.3 连续分配存储管理方式

连续分配方式,是指为一个用户程序分配一个连续的内存空间。
可分为四类:单一连续分配、固定分区分配、动态分区分配以及动态重定位分区分配算法。

4.3.1 单一连续分配

单一连续分配是最简单的一种存储管理方式,但只能用于单用户、单任务的操作系统中。

在单道程序环境下,把内存分为系统区和用户区两部分,系统区仅提供给 OS 使用,通常是放在内存的低址部分;用户区是指除系统区以外的全部内存空间,提供给用户使用。

4.3.2 固定分区分配

固定分区式分配是是最早出现的,最简单的一种可运行多道程序的存储管理方式。

将内存用户空间划分为若干个固定大小的区域,在每个分区中只装入一道作业,这样,把用户空间划分为几个分区,便允许有几道作业并发运行。当有一空闲分区时,便可以再从外存的后备作业队列中选择一个适当大小的作业装入该分区,当该作业结束时,又可再从后备作业队列中找出另一作业调入该分区。

划分分区的方法:

  1. 分区大小相等(指所有的内存分区大小相等)。

    缺点:缺乏灵活性,即程序太小时,会造成内存空间的浪费;程序太大时,一个分区又不足以装入程序,使程序无法运行。

  2. 分区大小不等。

    把内存区划分成含有多个较小的分区、适量的中等分区及少量的大分区。

4.3.3 动态分区分配

动态分区分配是根据进程的实际需要,动态地为之分配内存空间。

1、动态分区分配中的数据结构

用来描述空闲分区和已分配分区的情况。
常用的数据结构有以下两种形式:空闲分区表、空闲分区链。

2、动态分区分配算法

详见4.3.4和4.3.5

3、分区分配操作

在动态分区存储管理方式中,主要的操作是分配内存回收内存

  1. 分配内存

    设请求的分区大小为 u.size,表中每个空闲分区的大小可表示为m.size。若 m.size-u.size≤size(size 是事先规定的不再切割的剩余分区的大小),说明多余部分太小,可不再切割,将整个分区分配给请求者;否则(即多余部分超过 size),从该分区中按请求的大小划分出一块内存空间分配出去,余下的部分仍留在空闲分区链(表)中。然后,将分配区的首址返回给调用者。

  2. 回收内存

    当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链(表)中找到相应的插入点,此时可能出现以下四种情况之一:

    1. 回收区与插入点的前一个空闲分区 F1相邻接,见图 (a)。

      此时应将回收区与插入点的前一分区合并,不必为回收分区分配新表项,而只需修改其前一分区 F1的大小。

    2. 回收分区与插入点的后一空闲分区 F2相邻接,见图 (b)。

      此时也可将两分区合并,形成新的空闲分区,但用回收区的首址作为新空闲区的首址,大小为两者之和。

    3. 回收区同时与插入点的前、后两个分区邻接,见图 (c)。

      此时将三个分区合并,使用 F1的表项和 F1的首址,取消 F2的表项,大小为三者之和。

    4. 回收区既不与 F1邻接,又不与 F2邻接。
      这时应为回收区单独建立一新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置。

4.3.4 基于顺序搜索的动态分区分配算法

1、首次适应算法(first fit,FF)

FF 算法要求空闲分区链以地址递增的次序链接。在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止;然后再按照作业的大小,从该分区中划出一块内存空间分配给请求者,余下的空闲分区仍留在空闲链中。若从链首直至链尾都不能找到一个能满足要求的分区,则此次内存分配失败,返回。

优点:优先利用内存中低址部分的空闲分区,保留了高址部分的大空闲区。

缺点:会留下许多难以利用的、很小的空闲分区,会增加查找可用空闲分区时的开销。

2、循环首次适应算法(next fit,NF)

由首次适应算法演变而成的。在为进程分配内存空间时,不再是每次都从链首开始查找,而是从上次找到的空闲分区的下一个空闲分区开始查找,直至找到一个能满足要求的空闲分区,从中划出一块与请求大小相等的内存空间分配给作业。

优点:使内存中的空闲分区分布更均匀,减少了查找空闲分区时的开销。

缺点:缺乏大的空闲分区。

3、最佳适应算法(best fit,BF)

所谓“最佳”是指每次为作业分配内存时,总是把能满足要求、又是最小的空闲分区分配给作业,避免“大材小用”。该算法要求将所有的空闲分区按其容量以从小到大的顺序形成一空闲分区链。

优点:第一次找到的能满足要求的空闲区是最佳的。

缺点:留下许多难以利用的小空闲区,效果最差。

4、最坏适应算法(worst fit,WF)

最坏适应分配算法要扫描整个空闲分区表或链表,总是挑选一个最大的空闲区分割给作业使用。

优点:使剩下的空闲区不至于太小,产生碎片的几率最小,对中、小作业有利,查找效率很高。

缺点:缺乏大的空闲分区。

4.3.5 基于索引搜索的动态分区分配算法

1、快速适应算法(quick fit)

该算法又称为分类搜索法,是将空闲分区根据其容量大小进行分类,对于每一类具有相同容量的所有空闲分区,单独设立一个空闲分区链表,这样,系统中存在多个空闲分区链表,同时在内存中设立一张管理索引表,该表的每一个表项对应了一种空闲分区类型,并记录了该类型空闲分区链表表头的指针。

优点:查找效率高,仅需要根据进程的长度,寻找到能容纳它的最小空闲区链表,并取下第一块进行分配即可。

缺点:在分区归还主存时算法复杂,系统开销较大。空闲分区划分越细,浪费则越严重,典型的以空间换时间。

2、伙伴系统

固定分区方式限制了活动进程的数目,当进程大小与空闲分区大小不匹配时,内存空间利用率很低。动态分区方式算法复杂,回收空闲分区时需要进行分区合并等,系统开销较大。伙伴系统方式是对以上两种内存方式的一种折衷方案。

3、哈希算法

哈希算法就是利用哈希快速查找的优点,以及空闲分区在可利用空间表中的分布规律,建立哈希函数,构造一张以空闲分区大小为关键字的哈希表,该表的每一个表项记录了一个对应的空闲分区链表表头指针。当进行空闲分区分配时,根据所需空闲分区大小,通过哈希函数计算,即得到在哈希表中的位置,从中得到相应的空闲分区链表,实现最佳分配策略。

4.3.6 动态可重定位分区分配

1、紧凑

如果在系统中只有若干个小的分区,即使它们容量的总和大于要装入的程序,但由于这些分区不相邻接,也无法把该程序装入内存。这种不能被利用的小分区称为“零头”或“碎片”。

通过移动内存中作业的位置,以把原来多个分散的小分区拼接成一个大分区的方法,称为“拼接”或“紧凑”。

2、动态重定位

在动态运行时装入的方式中,作业装入内存后的所有地址都仍然是相对地址,程序指令要真正执行时才将相对地址转换为物理地址

重定位寄存器用来存放程序(数据)在内存中的起始地址。程序在执行时,真正访问的内存地址是相对地址与重定位寄存器中的地址相加而形成的。

地址变换过程是在程序执行期间,随着对每条指令或数据的访问自动进行的,故称为动态重定位

3、动态重定位分区分配算法

动态重定位分区分配算法与动态分区分配算法基本上相同,差别仅在于:增加了紧凑的功能。


4.4 对换

对换技术也称为交换技术。

4.4.1 多道程序环境下的对换技术

1、对换的引入

所谓对换(Swapping),是指把内存中暂时不能运行的进程或者暂时不用的程序和数据调出到外存上,以便腾出足够的内存空间,再把已具备运行条件的进程或进程所需要的程序和数据调入内存。

对换是提高内存利用率的有效措施,可以直接提高处理机的利用率和系统吞吐量。

2、对换的类型

根据每次对换时所对换的数量,可分为两类:

  1. 整体对换

    如果对换是以整个进程为单位的,便称之为“整体对换”或“进程对换”。

    目的:解决内存紧张问题,提高内存的利用率和系统的吞吐量。

    广泛应用于多道程序系统中,作为处理机的中级调度。

  2. 页面(分段)对换

    如果对换是以“页”或“段”为单位进行的,则分别称之为“页面对换”或“分段对换”,统称为“部分对换”。

    这种对换方法是实现请求分页和请求分段式存储管理的基础,其目的是为了支持虚拟存储系统。

    为了实现进程对换,系统必须能实现三方面的功能:对对换空间的管理、进程的换出和进程的换入

4.4.2 对换的空间管理

1、对换空间管理的主要目标

在具有对换功能的 OS 中,通常把磁盘空间分为文件区对换区

  • 文件区管理的主要目标:提高文件存储空间的利用率。
    因此,对文件区采取离散分配方式。
  • 对换空间管理的主要目标:提高进程换入和换出的速度。
    因此,对对换区采取连续分配方式,较少考虑外存碎片问题。

2、对换区空闲盘块管理中的数据结构

其形式与内存在动态分区分配方式中所用数据结构相似,即同样可以用空闲分区表空闲分区链。在空闲分区表中的每个表目中应包含两项,即对换区的首址及其大小,分别用盘块号和盘块数表示。

3、对换空间的分配与回收

与动态分区方式时的内存分配与回收方法雷同。其分配算法可以是首次适应算法、循环首次适应算法或最佳适应算法。

4.4.3 进程的换出和换入

1、进程的换出

每当一进程由于创建子进程而需要更多的内存空间,但又无足够的内存空间等情况发生时,系统应将某进程换出。

过程:

系统首先选择处于阻塞状态且优先级最低的进程作为换出进程,然后启动磁盘,将该进程的程序和数据传送到磁盘的对换区上。
若传送过程未出现错误,便可回收该进程所占用的内存空间,并对该进程的进程控制块做相应的修改。

2、进程的换入

系统应定时地查看所有进程的状态,从中找出“就绪”状态但已换出的进程,将其中换出时间最久(换出到磁盘上)的进程作为换入进程,将之换入,直至已无可换入的进程或无可换出的进程为止。


4.5 分页存储管理方式

如果离散分配的基本单位是页,则称为分页存储管理方式
如果离散分配的基本单位是段,则称为分段存储管理方式
段页式存储管理方式是分页和分段存储管理方式相结合的产物。

4.5.1 分页存储管理的基本方法

1、页面和物理块

分页存储管理是将一个进程的逻辑地址空间分成若干个大小相等的片,称为页面或页,并为各页加以编号,从 0 开始。相应地,也把内存空间分成与页面相同大小的若干个存储块,称为(物理)块或页框(frame),同样为它们加以编号。由于进程的最后一页经常装不满一块而形成了不可利用的碎片,称之为 “页内碎片”。

页面过小:可使内存碎片减小,从而减少内存碎片的总空间,有利于提高内存利用率;但也会使每个进程占用较多的页面,导致进程的页表过长,占用大量内存;还会降低页面换进换出的效率。

页面过大:可以减少页表的长度,提高页面换进换出的速度,但又会使页内碎片增大。

2、地址结构

分页地址中的地址结构含有两部分:前一部分为页号 P,后一部分为位移量 W,即页内地址

若给定一个逻辑地址空间中的地址为 A,页面大小 L,则页号 P 和页内地址 d :
\(P = INT[\dfrac{A}{L}](整除),d = [A] MOD L(取余)\)

3、页表

为保证进程正确运行,即能在内存中找到每个页面所对应的物理块,系统又为每个进程建立了一张页面映像表,简称页表

页表的作用是实现从页号到物理块号的地址映射

4.5.2 地址变换机构

为了能将用户地址空间中的逻辑地址变换为内存空间中的物理地址,在系统中必须设置地址变换机构。该机构的基本任务是实现从逻辑地址到物理地址的转换

基本的地址变换机构

页表的功能可以由一组专门的寄存器来实现。一个页表项用一个寄存器。

页表大多驻留在内存中。在系统中只设置一个页表寄存器 PTR(Page-Table Register),在其中存放页表在内存的始址和页表的长度。

进程未执行时,页表的始址和页表长度存放在本进程的 PCB 中。当调度程序调度到某进程时,才将这两个数据装入页表寄存器中。故只需一个页表寄存器。

地址变换过程:

当进程要访问某个逻辑地址中的数据时,分页地址变换机构会自动地将有效地址(相对地址)分为页号和页内地址两部分,再以页号为索引去检索页表。查找操作由硬件执行。
在执行检索之前,先将页号与页表长度进行比较,如果页号大于或等于页表长度,则表示本次所访问的地址已超越进程的地址空间,产生一地址越界中断。
若未出现越界错误,则将页表始址与页号和页表项长度的乘积相加,便得到该表项在页表中的位置,从中得到该页的物理块号,将之装入物理地址寄存器中。与此同时,再将有效地址寄存器中的页内地址送入物理地址寄存器的块内地址字段中。

具有快表的地址变换机构

为了提高地址变换速度,可在地址变换机构中增设一个具有并行查寻能力的特殊高速缓冲寄存器,又称为“联想寄存器”(Associative Memory),或称为“快表”,在 IBM 系统中又取名为 TLB(Translation Lookaside Buffer),用以存放当前访问的那些页表项。

变换过程:

在 CPU 给出有效地址后,由地址变换机构自动地将页号 P 送入高速缓冲寄存器,并将此页号与高速缓存中的所有页号进行比较。
若其中有与此相匹配的页号,便表示所要访问的页表项在快表中。直接从快表中读出该页所对应的物理块号,并送到物理地址寄存器中。
如在快表中未找到对应的页表项,则还须再访问内存中的页表,找到后,把从页表项中读出的物理块号送地址寄存器;同时,再将此页表项存入快表的一个寄存器单元中,亦即,重新修改快表。
如果联想寄存器已满,则 OS 必须找到一个老的且已被认为不再需要的页表项,将它换出。

4.5.3 访问内存的有效时间

从进程发出指定逻辑地址的访问请求,经过地址变换,到在内存中找到对应的实际物理地址单元并取出数据,所需要花费的总时间,称为内存的有效访问时间(Effective Access Time,EAT)。

假设访问一次内存的时间为t,则:
基本分页存储管理方式中的有效访问时间:EAT=2t
具有快表的分页存储管理方式中的有效访问时间:EAT= a×λ+(t+λ)(1-a)+t=2t+λ-t×a
(λ表示查找快表所需时间,a表示命中率)

4.5.4 两级和多级页表

两级页表

对于要求连续的内存空间来存放页表的问题,可利用将页表进行分页,并离散地将各个页面分别存放在不同的物理块中的办法来加以解决,同样也要为离散分配的页表再建立一张页表,称为外层页表(Outer Page Table),在每个页表项中记录了页表页面的物理块号。

逻辑地址结构:

两级页表结构:

虽然解决了对大页表无需大片存储空间的问题,但并未解决用较少的内存空间去存放大页表的问题。

解决方法:把当前需要的一批页表项调入内存,以后再根据需要陆续调入。

多级页表

将外层页表再进行分页,也就是将各分页离散地装入到不相邻接的物理块中,再利用第 2 级的外层页表来映射它们之间的关系。

4.5.5 反置页表

为减少页表占用的内存空间,引入了反置页表。

  • 一般页表:页表项按页号排序,页表项中内容是物理块号。
  • 反置页表:为每个物理块设置一个页表项,并按物理块的编号排序,内容则是页号和其所隶属进程的标识符。

地址变换

根据进程标识和页号,去检索反置页表。


4.6 分段存储管理方式

4.6.1 分段存储管理方式的引入

符合需求:

  1. 方便编程
  2. 信息共享
  3. 信息保护
  4. 动态增长
  5. 动态链接

4.6.2 分段系统的基本原理

1、分段

在分段存储管理方式中,作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息。其逻辑地址由段号(段名)和段内地址所组成。

地址结构:

2、段表

为保证程序能正常运行,能从物理内存中找出每个逻辑段所对应的位置,类似分页系统,在系统中为每个进程建立一张段映射表,简称 “段表”。
每个段在表中占有一个表项,其中记录了该段在内存中的起始地址(又称“基址”) 和段的长度。

3、地址变换机构

为了实现从进程的逻辑地址到物理地址的变换功能,在系统中设置了段表寄存器,用于存放段表始址和段表长度 TL。

地址变换过程:

将逻辑地址中的段号与段表长度TL 进行比较。
若 S>TL,表示段号太大,是访问越界,于是产生越界中断信号;
若未越界,则根据段表的始址和该段的段号,计算出该段对应段表项的位置,从中读出该段在内存的起始地址。

然后,检查段内地址 d 是否超过该段的段长 SL。
若超过,即 d>SL,同样发出越界中断信号;
若未越界,则将该段的基址 d 与段内地址相加,即可得到要访问的内存物理地址。

4、分页和分段的主要区别

分页 分段
页是信息的物理单位,对用户不可见 段是信息的逻辑单位,对用户可见
分页的目的是提高内存的利用率 分段的目的是更好地满足用户的需求
页的大小是固定且由系统决定 段的长度不固定,由用户所编写程序决定
分页的用户程序地址空间是一维的 分段的用户程序地址空间是二维的

4.6.3 信息共享

分段系统的一个突出优点,是易于实现段的共享,即允许若干个进程共享一个或多个分段,且对段的保护也十分简单易行。

  • 分页系统

    在分页系统中,虽然也能实现程序和数据的共享,但远不如分段系统来得方便。

  • 分段系统

    在分段系统中,实现共享则容易得多,只需在每个进程的段表中为文本编辑程序设置一个段表项。

4.6.4 段页式存储管理方式

基本原理

段页式系统的基本原理,是分段和分页原理的结合,即先将用户程序分成若干个段,再把每个段分成若干个页,并为每一个段赋予一个段名。

在段页式系统中,其地址结构由段号、段内页号及页内地址三部分所组成。
段表内容为页表始址和页表长度

地址变换过程

配置一个段表寄存器,其中存放段表始址和段表长 TL。
进行地址变换时,首先利用段号 S,将它与段表长 TL 进行比较。
若 S<TL,表示未越界,于是利用段表始址和段号来求出该段所对应的段表项在段表中的位置,从中得到该段的页表始址,并利用逻辑地址中的段内页号 P 来获得对应页的页表项位置,从中读出该页所在的物理块号 b,再利用块号 b 和页内地址来构成物理地址。


posted @ 2023-02-09 16:34  0dot7  阅读(159)  评论(0编辑  收藏  举报