操作系统---存储器管理

存储器的层次结构

  • 最高层为CPU寄存器 中间为主存 最底层是辅存

多级存储器结构

  • 根据具体的功能细分为CPU寄存器(寄存器)、主存(高速缓存、主存储器、磁盘缓存)、辅存、(固定磁盘、可移动存储介质),在存储层次中越往上,存储介质的访问速度越快,价格也越高,相对存储容量也越小。其中,寄存器、高速缓存、主存储器和磁盘缓存均属于存储管理的管辖范畴,掉电后它们存储的信息不再存在,固定磁盘和可移动存储介质属于设备管理的管辖范畴,它们存储的信息将被长期保存。
  • 在计算机系统的存储层次中,寄存器和主存储器又被称为可执行存储器,对于存放于其中的信息,与存放于辅存中的信息相比较而言,计算机所采用的访问机制是不同的,所需耗费的时间也是不同的,进程可以在很少的时钟周期内使用一条load或store指令对可执行存储器进行访问,但对辅存的访问则需要通过I/O设备实现,在访问中将涉及到中断、设备驱动程序以及物理设备的运行,所需耗费的时间远远高于访问可执行存储器的时间。

主存储器与寄存器

  • 主存储器(简称内存或主存):是计算机系统中的主要部件,用于保存进程运行时的程序和数据,也称可执行存储器,CPU的控制部件只能从主存储器中取得指令和数据,数据能够从主存储器读取并将它们装入到寄存器中,或者从寄存器存入到主存储器,CPU与外围设备交换的信息一般也依托于主存储器地址空间。
  • 寄存器:寄存器具有与处理机相同的速度,访问速度最快,完全能与CPU协调工作。寄存器用于加速存储器的访问速度。

高速缓存和磁盘缓存

  • 高速缓存:是介于寄存器和存储器之间的存储器,主要用于备份主存中较常用的数据,以减少处理机对主存储器的访问次数,这样可大幅度地提高程序执行速度。

    高速缓存容量远大于寄存器,而比内存约小两到三个数量级左右,访问速度快于主存储器。通常,进程的程序和数据是存放在主存储器中,每当使用时,被临时复制到一个速度较快的高速缓存中。

    当 CPU访问一组特定信息时,首先检查它是否在高速缓存中,如果已存在,可直接从中取出使用,以避免访问主存,否则,再从主存中读出信息。由于高速缓存的速度越高价格也越贵,故有的计算机系统中设置了两级或多级高速缓存。紧靠内存的一级高速缓存的速度最高,而容量最小,二级高速缓存的容量稍大,速度也稍低。

  • 磁盘缓存:由于目前磁盘的I/O速度远低于对主存的访问速度,为了缓和IO和主存之间在速度上的不匹配,而设置了磁盘缓存,主要用于暂时存放频繁使用的一部分磁盘数据和信息,以减少访问磁盘的次数

    但磁盘缓存与高速缓存不同,它本身并不是一种实际存在的存储器,而是利用主存中的部分存储空间暂时存放从磁盘中读出(或写入)的信息,主存也可以看作是辅存的高速缓存,因为,辅存中的数据必须复制到主存方能使用,反之,数据也必须先存在主存中,才能输出到辅存。

程序的装入和链接

用户程序要在系统中运行,必须先将它装入内存,然后由编译程序(Compiler)对用户源程序进行编译,形成若干个目标模块(Object Module)链接,由链接程序(Linker)将编译后形成的目标模块以及它们所需要的库函数链接在一起,形成一个完整的装入模块(Load Module),由装入程序(Loader)将装入模块装入内存。

程序的装入

  • 绝对装入方式(Absolute Loading Mode)
    在编译时,如果知道程序将驻留在内存的什么位置,那么,编译程序将产生绝对地址的目标代码。只适用于单道程序环境。绝对装入程序按照装入模块中的地址,将程序和数据装入内存。装入模块被装入内存后,由于程序中的逻辑地址与实际内存地址完全相同,故不须对程序和数据的地址进行修改

    程序中所使用的绝对地址,既可在编译或汇编时给出,也可由程序员直接赋予,但在由程序员直接给出绝对地址时,不仅要求程序员熟悉内存的使用情况,而且一旦程序或数据被修改后,可能要改变程序中的所有地址,因此,通常是在程序中采用符号地址,然后在编译或汇编时,再将这些符号地址转换为绝对地址。

  • 可重定位装入方式(Relocation Loading Mode)
    在多道程序环境下,编译程序不可能预知经编译后所得到的目标模块应放在内存的何处。因此,对于用户程序编译所形成的若干个目标模块,它们的起始地址通常都是从0开始的,程序中的其它地址也都是相对于起始地址计算的。可将装入模块装入到内存中任何允许的位置,故可用于多道程序环境

    但该方式并不允许程序运行时在内存中移动位置,根据内存的当前情况,将装入模块装入到内存的适当位置,把在装入时对目标程序中指令和数据的修改过程称为重定位,又因为地址变换通常是在装入时一次完成的,以后不再改变,故称为静态重定位

  • 动态运行时的装入方式(Dynamic Run-time Loading)
    动态运行时的装入程序在把装入模块装入内存后,并不立即把装入模块中的相对地址转换为绝对地址,而是把这种地址转换推迟到程序真正要执行时才进行,因此,装入内存后的所有地址都仍是相对地址,为使地址转换不影响指令的执行速度,这种方式需要一个重定位寄存器的支持。

程序的链接

  • 静态链接(Static Linking)方式
    在程序运行之前,先将各目标模块及它们所需的库函数链接成一个完整的装配模块,以后不再拆开,运行时可直接将它装入内存,这几个目标模块装配成一个装入模块时,须解决以下两个问题: 对相对地址进行修改。变换外部调用符号:将每个模块中所用的外部调用符号也都变换为相对地址。

  • 装入时动态链接(Load-time Dynamic Linking)
    这是指将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的链接方式,即在装入一个目标模块时,若发生一个外部模块调用事件,将引起装入程序去找出相应的外部目标模块,并将它装入内存。便于修改和更新,便于实现对目标模块的共享。

  • 运行时动态链接(Run-time Dynamic Linking)
    应用程序在运行时,每次要运行的模块可能是不相同的,只能是将所有可能要运行到的模块全部都装入内存 ,这种链接方式是将对某些模块的链接推迟到程序执行时才进行链接,在执行过程中, 当发现一个被调用模块尚未装入内存时,立即由 OS 去找到该模块并将之装入内存,把它链接到调用者模块上。这样不仅可加快程序的装入过程,而且可节省大量的内存空间

连续分配方式

单一连续分配

只能用于单用户、单任务的操作系统中。采用这种存储管理方式时,可把内存分为系统区和用户区两部分。系统区仅提供给 OS 使用,通常是放在内存的低址部分,用户区是指除系统区以外的全部内存空间,提供给用户使用 。在用户区内存中,仅装有一道用户程序,即整个内存的用户空间由该程序独占,这样的存储器分配方式被称为单一连续分配方式。

固定分区分配

最简单的一种可运行多道程序的存储管理方式。将内存用户空间划分为若干个固定大小的区域,在每个分区中只装入一道作业。这样,便允许有几道作业并发运行。当有一空闲分区时,便可以再从外存的后备作业队列中选择一个适当大小的作业装入该分区。

  • 划分分区的方法:
    分区大小相等 
    缺乏灵活性,即当程序太小时,会造成内存空间的浪费;当程序太大时,一个分区又不足以装入该程序,致使该程序无法运行。这种划分方式被用于利用一台计算机去控制多个相同对象的场合。

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

  • 内存分配
    为了便于内存分配,通常将分区按其大小进行排队,并为之建立一张分区使用表,其中各表项包括每个分区的起始地址、大小及状态(是否已分配) 。当有一用户程序要装入时,由内存分配程序检索该表,从中找出一个能满足要求的、尚未分配的分区,将之分配给该程序,然后将该表项中的状态置为“已分配”;若未找到大小足够的分区,则拒绝为该用户程序分配内存。

动态分区分配

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

  • 动态分区分配中的数据结构
    空闲分区表:在系统中设置一张空闲分区表,用于记录每个空闲分区的情况。每个空闲分区占一个表目,表目中包括分区号、分区大小和分区始址等数据项。

    空闲分区链:为了实现对空闲分区的分配和链接,在每个分区的起始部分设置一些用于控制分区分配的信息以及用于链接各分区所用的前向指针,在分区尾部则设置一后向指针,通过前、后向链接指针,可将所有的空闲分区链接成一个双向链。为了检索方便,在分区尾部重复设置状态位和分区大小表目。当分区被分配出去以后,把状态位由“0”改为“1” 此时,前、后向指针已无意义 。

  • 分区分配算法
    首次适应(first fit,FF)算法
    FF算法要求空闲分区链以地址递增的次序链接。在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止。然后再按照作业的大小,从该分区中划出一块内存空间,分配给请求者,余下的空闲分区仍留在空闲链中。若从链首直至链尾都不能找到一个能满足要求的分区,则表明系统中已没有足够大的内存分配给该进程,内存分配失败。

    该算法倾向于优先利用内存中低址部分的空闲分区,从而保留了高址部分的大空闲区,这给为以后到达的大作业分配大的内存空间创造了条件,低址部分不断被划分,会留下许多难以利用的、很小的空闲分区,而每次查找又都是从低址部分开始,这无疑会增加查找可用空闲分区时的开销。

    循环首次适应(next fit,NF)算法
    为避免低址部分留下许多很小的空闲分区,以及减少查找可用空闲分区的开销,在为进程分配内存空间时,不再是每次都从链首开始查找,而是从上次找到的空闲分区的下一个空闲分区开始,直到找到一个能满足要求的空闲分区,从中划出一块与请求大小相等的内存空间分配给作业。为实现该算法,应设置一起始查寻指针,用于指示下一次起始查寻的空闲分区,并采用循环查找方式,即如果最后一个(链尾)空闲分区的大小仍不能满足要求,则应返回到第一个空闲分区,比较其大小是否满足要求。找到后,应调整起始查寻指针。

    该算法能使内存中的空闲分区分布得更均匀,从而减少了查找空闲分区时的开销,但这样会缺乏大的空闲分区。

    最佳适应(best fit,BF)算法
    所谓“最佳”是指,每次为作业分配内存时,总是把能满足要求、又是最小的空闲分区分配给作业。为了加速寻找,该算法要求将所有的空闲分区按其容量以从小到大的顺序形成空闲分区链。每次分配后所切割下来的剩余部分总是最小的,这样,在存储器中会留下许多难以利用的小空闲区。

    最坏适应(worst fit,WF)算法
    它在扫描整个空闲分区表或链表时,总是挑选一个最大的空闲区,从中分割一部分存储空间给作业使用,以至于存储器中缺乏大的空闲分区。该算法要求将所有的空闲分区按其容量以从大到小的顺序形成一空闲分区链,查找时只要看第一个分区能否满足作业要求。

    可使剩下的空闲区不至于太小,产生碎片的几率最小,对中、小作业有利,同时最坏适应分配算法查找效率很高,会使存储器中缺乏大的空闲分区。

    快速适应(quick fit)算法
    该算法又称为分类搜索法,是将空闲分区根据其容量大小进行分类,对于每一类具有相同容量的所有空闲分区,单独设立一个空闲分区链表,这样系统中存在多个空闲分区链表,同时,在内存中设立一张管理索引表,其中的每一个索引表项对应了一种空闲分区类型,记录该类型空闲分区链表表头的指针 。查找效率高,仅需要根据进程的长度,寻找到能容纳它的最小空闲区链表,并取下第一块进行分配即可。

    该算法在进行空闲分区分配时,不会对任何分区产生分割,所以能保留大的分区,也不会产生内存碎片。分区归还主存时算法复杂,系统开销较大。该算法在分配空闲分区时是以进程为单位,一个分区只属于一个进程,因此在为进程所分配的一个分区中,存在一定的浪费,空闲分区划分越细,浪费则越严重,整体上会造成可观的存储空间浪费,这是典型的以空间换时间的作法。

  • 回收内存
    当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链(表)中找到相应的插 入点:

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

    回收分区与插入点的后一空闲分区 F2相邻接,此时也可将两分区合并, 形成新的空闲分区,但用回收区的首址作为新空闲区的首址,大小为两者之和。

    回收区同时与插入点的前、后两个分区邻接,此时将三个分区合并, 使用 F1的表项和 F1的首址,取消 F2的表项,大小为三者之和。

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

伙伴系统(buddy system)

  • 该算法规定,无论已分配分区或空闲分区,其大小均为2的k次幂(k为整数,1≤k≤m),通常2m是整个可分配内存的大小(也就是最大分区的大小)。假设系统的可利用空间容量为2m 个字,则系统开始运行时,整个内存区是一个大小为2m的空闲分区。在系统运行过程中,由于不断地划分,将会形成若干个不连续的空闲分区,将这些空闲分区按分区的大小进行分类,对于具有相同大小的所有空闲分区,单独设立一个空闲分区双向链表,这样,不同大小的空闲分区形成了k个空闲分区链表。

  • 当需要为进程分配一个长度为 n 的存储空间时,首先计算一个 i 值,使 2i-1<n≤2i,然后在空闲分区大小为 2i的空闲分区链表中查找。若找到,即把该空闲分区分配给进程。否则,表明长度为2i的空闲分区已经耗尽,则在分区大小为 2i+1的空闲分区链表中寻找。若存在 2i+1的一个空闲分区,则把该空闲分区分为相等的两个分区,这两个分区称为一对伙伴,其中的一个分区用于分配,而把另一个加入分区大小为 2i的空闲分区链表中。以此类推。由此可见,在最坏的情况下,可能需要对2k的空闲分区进行 k次分割才能得到所需分区,与一次分配可能要进行多次分割一样,一次回收也可能要进行多次合并。如回收大小为 2i的空闲分区时,若事先已存在2i的空闲分区时,则应将其与伙伴分区合并为大小为 2i+1的空闲分区,若事先已存在2i+1的空闲分区时,又应继续与其伙伴分区合并为大小为2i+2的空闲分区,依此类推。

    在伙伴系统中,其分配和回收的时间性能取决于查找空闲分区的位置和分割、合并空闲分区所花费的时间

哈希算法

  • 在上述的分类搜索算法和伙伴系统算法中,需要在一张管理索引表中查找到所需空间大小所对应的表项,从中得到对应的空闲分区链表表头指针,从而通过查找得到一个空闲分区如果对空闲分区分类较细,则相应的空闲分区链表也较多,因此选择合适的空闲链表的开销也相应增加,且时间性能降低。

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

可重定位分区分配

  • 紧凑:
    通过移动内存中作业的位置,以把原来多个分散的小分区拼接成一个大分区的方法,称为“拼接”或“紧凑”。由于经过紧凑后的某些用户程序在内存中的位置发生了变化,此时若不对程序和数据的地址加以修改(变换),则程序必将无法执行,为此,在每次“紧凑”后,都必须对移动了的程序或数据进行重定位。

  • 动态重定位
    动态运行时装入的方式中,作业装入内存后的所有地址仍然都是相对(逻辑)地址,而将相对地址转换为绝对(物理)地址的工作被推迟到程序指令要真正执行时进行。为使地址的转换不会影响到指令的执行速度,必须有硬件地址变换机构的支持,即须在系统中增设一个重定位寄存器,用它来存放程序(数据)在内存中的起始地址。程序在执行时,真正访问的内存地址是相对地址与重定位寄存器中的地址相加而形成的。

    当系统对内存进行了“紧凑”而使若干程序从内存的某处移至另一处时,不需对程序做任何修改。只要用该程序在内存的新起始地址,去置换原来的起始地址即可。

  • 动态重定位分区分配算法
    动态重定位分区分配算法与动态分区分配算法基本上相同,差别仅在于:在这种分配算法中,增加了紧凑的功能。通常,当该算法不能找到一个足够大的空闲分区以满足用户需求时,如果所有的小的空闲分区的容量总和大于用户的要求,这时便须对内存进行“紧凑”,将经“紧凑”后所得到的大空闲分区分配给用户,如果所有的小的空闲分区的容量总和仍小于用户的要求,则返回分配失败信息。

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

  • 回收内存
    当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链(表)中找到相应的插入点。

对换(Swapping)

  • 对换的引入
    在多道程序环境下,一方面,在内存中的某些进程由于某事件尚未发生而被阻塞运行,但它却占用了大量的内存空间,甚至有时可能出现在内存中所有进程都被阻塞,而无可运行之进程,迫使CPU停止下来等待的情况。另一方面,却又有着许多作业,因内存空间不足,一直驻留在外存上,而不能进入内存运行。显然这会使系统吞吐量下降,所谓“对换”,是指把内存中暂时不能运行的进程或者暂时不用的程序和数据调出到外存上,以便腾出足够的内存空间,再把已具备运行条件的进程或进程所需要的程序和数据调入内存。

    对换是提高内存利用率的有效措施
    如果对换是以整个进程为单位的,便称之为“整体对换”或“进程对换”。这种对换被广泛地应用于分时系统中,其目的是用来解决内存紧张问题,并可进一步提高内存的利用率。而如果对换是以“页”或“段”为单位进行的,则分别称之为“页面对换”或“分段对换”,又统称为“部分对换”。

  • 覆盖技术:把一个大的程序划分为一系列覆盖,每个覆盖是一个相对独立的程序单位,把程序执行时并不要求同时装入内存的覆盖组成一组,成为覆盖段,这个覆盖段分配到同一个存储区域,这个存储区域成为覆盖区,它与覆盖段一一对应。覆盖段的大小由覆盖段中大的覆盖来确定。(为了解决内存容量太小的问题,打破了必须将一个程序全部信息装入内存后才能运行的限制)

  • 与覆盖技术相比,交换技术不要求程序员给出的程序段之间的覆盖结构;交换技术主要在进程和作业之间进行,覆盖技术主要在同一个进程或作业中进行;覆盖技术只能覆盖与覆盖程序段无关的程序段,交换进程由换出和换入两个过程组成。

  • 对换空间的管理:
    在具有对换功能的 OS 中,通常把外存分为文件区和对换区。前者用于存放文件,后者用于存放从内存换出的进程。

    由于通常的文件都是较长久地驻留在外存上,故对文件区管理的主要目标,是提高文件存储空间的利用率。为此,对文件区采取离散分配方式。然而,进程在对换区中驻留的时间是短暂的,对换操作又较频繁,故对对换空间管理的主要目标, 是提高进程换入和换出的速度。为此,采取的是连续分配方式,较少考虑外存中的碎片问题。

    为了能对对换区中的空闲盘块进行管理,在系统中应配置相应的数据结构(空闲分区表或空闲分区链),以记录外存的使用情况。在空闲分区表中的每个表目中应包含两项,即对换区的首址及其大小,分别用盘块号和盘块数表示。由于对换分区的分配是采用连续分配方式,因而对换空间的分配与回收,与动态分区方式时的内存分配与回收方法雷同。

  • 进程的换出:
    每当一进程由于创建子进程而需要更多的内存空间,但又无足够的内存空间等情况发生时,系统应将某进程换出。系统首先选择处于阻塞状态且优先级最低的进程作为换出进程,然后启动磁盘,将该进程的程序和数据传送到磁盘的对换区上。若传送过程未出现错误,便可回收该进程所占用的内存空间,并对该进程的进程控制块做相应的修改。

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

基本分页存储管理方式

页面与页表

  • 分页存储管理是将一个进程的逻辑地址空间分成若干个大小相等的片,称为页面或页,并为各页加以编号。相应地,也把内存空间分成与页面相同大小的若干个存储块,称为(物理)块或页框(frame),也同样为它们加以编号。在为进程分配内存时,以块为单位将进程中的若干个页分别装入到多个可以不相邻接的物理块中

    由于进程的最后一页经常装不满一块而形成了不可利用的碎片,称之为“页内碎片”。

  • 页面大小
    页面若太小,一方面虽然可使内存碎片减小,从而减少了内存碎片的总空间,有利于提高内存利用率。但另一方面也会使每个进程占用较多的页面,从而导致进程的页表过长,占用大量内存。此外,还会降低页面换进换出的效率。

    如果选择的页面较大,虽然可以减少页表的长度,提高页面换进换出的速度,但却又会使页内碎片增大。

    因此,页面的大小应选择适中,且页面大小应是 2的幂,通常 为 512 B~8 KB。

  • 地址结构   
    页号(31-12)位移量(11-0)

    对某特定机器,其地址结构是一定的,若给定一个逻辑地址空间中的地址为A,页面的大小为L,则页号P和页内地址d可按下式求得:P=INT(A/L),D=[A]MOD L。

  • 页表
    在分页系统中,允许将进程的各个页离散地存储在内存的任一物理块中。为保证进程仍然能够正确地运行,即能在内存中找到每个页面所对应的物理块,系统又为每个进程建立了一张页面映像表,简称页表。实现从页号到物理块号的地址映射

    在进程地址空间内的所有页,依次在页表中有一页表项,其中记录了相应页在内存中对应的物理块号,在配置了页表后,进程执行时,通过查找该表,即可找到每页在内存中的物理块号。

    即使在简单的分页系统中,也常在页表的表项中设置一存取控制字段,用于对该存储块中的内容加以保护,当存取控制字段仅有一位时,可用来规定该存储块中的内容是允许读/写,还是只读。若存取控制字段为二位,则可规定为读/写、只读和只执行等存取方式,如果有一进程试图去写一个只允许读的存储块时,将引起操作系统的一次中断。

地址变换机构

  • 将用户地址空间中的逻辑地址变换为内存空间中的物理地址。由于页内地址和物理地址是一一对应的,因此,地址变换机构的任务实际上只是将逻辑地址中的页号,转换为内存中的物理块号。

  • 基本的地址变换机构
    页表的功能可以由一组专门的寄存器来实现,一个页表项用一个寄存器,页表大多驻留在内存中。在系统中只设置一个页表寄存器 PTR(Page-Table Register),在其中存放页表在内存的始址和页表的长度。进程未执行时,页表的始址和页表长度存放在本进程的 PCB 中。当调度程序调度到某进程时,才将这两个数据装入页表寄存器中。因此,在单处理机环境下,虽然系统中可以运行多个进程,但只需一个页表寄存器。

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

  • 具有快表的地址变换机构
    由于页表是存放在内存中的,这使CPU在每存取一个数据时,都要两次访问内存。第一次是访问内存中的页表,从中找到指定页的物理块号,再将块号与页内偏移量W拼接,以形成物理地址。第二次访问内存时,才是从第一次所得地址中获得所需数据(或向此地址中写入数据)。

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

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

  • 快表:页表的一部分或全部内容

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

    假设访问一次内存的时间为t,在基本分页存储管理方式中,有效访问时间分为第一次访问内存时间与第二次访问内存时间之和:EAT = t + t = 2t。在引入快表的分页存储管理方式中,通过快表查询,可以直接得到逻辑页所对应的物理块号,由此拼接形成实际物理地址,减少了一次内存访问,缩短了进程访问内存的有效时间。

    快表中查找到所需表项存在着命中率的问题。所谓命中率,是指使用快表并在其中成功查找到所需页面的表项的比率。这样,在引入快表的分页存储管理方式中,有效访问时间为EAT=а×λ+(1—а) (t+λ) +t=2t+λ—t×а。λ表示查找快表所需要的时间,а表示命中率,t表示访问一次内存所需要的时间,可见,引入快表后的内存有效访问时间分为查找到逻辑页对应的页表项的平均时间а × λ + (t + λ)(1 - а),以及对应实际物理地址的内存访问时间t。

两级和多级页表

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

  • 地址结构:外层页号(P1 31-22)外层页内地址(P2 21-12)页内地址(d 11-0)

  • 为了方便实现地址变换,在地址变换机构中,同样需要增设一个外层页表寄存器,用于存放外层页表的始址,并利用逻辑地址中的外层页号作为外层页表的索引,从中找到指定页表分页的始址,再利用P2作为指定页表分页的索引,找到指定的页表项,其中即含有该页在内存的物理块号,用该块号P和页内地址d即可构成访问的内存物理地址。

  • 上述对页表施行离散分配的方法,只用离散分配空间的办法并未减少页表所占用的内存空间。解决方法是把当前需要的一批页表项调入内存,以后再根据需要陆续调入。在采用两级页表结构的情况下,对于正在运行的进程,必须将其外层页表调入内存,而对页表则只需调入一页或几页,为了表征某页的页表是否已经调入内存,还应在外层页表项中增设一个状态位 S。进程运行时,地址变换机构根据逻辑地址中的 P1,去查找外层页表,若所找到的页表项中的状态位为 0,则产生一中断信号,请求 OS 将该页表分页调入内存。

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

  • 反置页表(Inverted Page Table)

    在分页系统中,为每个进程配置了一张页表,进程逻辑地址空间中的每一页,在页表中都对应有一个页表项,在现代计算机系统中,通常允许一个进程的逻辑地址空间非常大,因此就需要有许多的页表项,而因此也会占用大量的内存空间。

    一般页表的表项是按页号进行排序,页表项中的内容是物理块号。而反置页表是为每一个物理块设置一个页表项并按物理块号排序,其中的内容是页号及其隶属进程的标识符。系统只维护一张反置页表。

    地址变换
    在利用反置页表进行地址变换时,是根据进程标识符和页号,去检索反置页表。如果检索到与之匹配的页表项,则该页表项(中)的序号i便是该页所在的物理块号。可用该块号与页内地址一起构成物理地址送内存地址寄存器。若检索了整个反置页表仍未找到匹配的页表项,则表明此页尚未装入内存,对于不具有请求调页功能的存储器管理系统,此时则表示地址出错,对于具有请求调页功能的存储器管理系统,此时应产生请求调页中断,系统将把此页调入内存。

基本分段存储管理方式

分段存储管理方式的引入

  • 方便编程
    通常,用户把自己的作业按照逻辑关系划分为若干个段,每个段都从0开始编址,并有自己的名字和长度。因此,程序员们都迫切地需要访问的逻辑地址是由段名(段号)和段内偏移量(段内地址)决定的,这不仅可以方便程序员编程,也可使程序非常直观,更具可读性

  • 信息共享
    在实现对程序和数据的共享时,是以信息的逻辑单位为基础的。分页系统中的“页”只是存放信息的物理单位(块),并无完整的逻辑意义。

  • 信息保护
    信息保护同样是以信息的逻辑单位为基础的,而且经常是以一个过程、函数或文件为基本单位进行保护的。

  • 动态增长
    在实际应用中,往往存在着一些段,尤其是数据段,在它们的使用过程中,由于数据量的不断增加,而使数据段动态增长,相应地它所需要的存储空间也会动态增加,然而,对于数据段究竟会增长到多大,事先又很难确切地知道。对此,很难采取预先多分配的方法进行解决。

分段系统的基本原理

  • 分段
    在分段存储管理方式中,作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息,分段地址中的地址具有如下结构:段号(31-16)段内地址(15-0)。每个段都从 0 开始编址,并采用一段连续的地址空间,段的长度由相应的逻辑信息组的长度决定,因而各段长度不等。

  • 段表
    为每个分段分配一个连续的分区。进程中的各个段,可以离散地装入内存中不同的分区中,为使程序能从物理内存中找出每个逻辑段所对应的位置,在系统中为每个进程建立一张段映射表,简称 “段表”。每个段在表中占有一个表项,其中记录了该段在内存中的起始地址(又称为“基址”) 和段的长度。段表可以存放在一组寄存器中,这样有利于提高地址转换速度,但更常见的是将段表放在内存中。在配置了段表后,执行中的进程可通过查找段表找到每个段所对应的内存区。

  • 地址变换机构
    设置了段表寄存器,用于存放段表始址和段表长度TL。在进行地址变换时,系统将逻辑地址中的段号与段表长度TL进行比较,若S>TL,表示段号太大,是访问越界,于是产生越界中断信号,若未越界,则根据段表的始址和该段的段号,计算出该段对应段表项的位置,从中读出该段在内存的起始地址。然后,再检查段内地址d是否超过该段的段长SL,若超过,即d>SL,同样发出越界中断信号,若未越界,则将该段的基址d与段内地址相加,即可得到要访问的内存物理地址。当段表放在内存中时,每要访问一个数据,须访问两次内存,从而极大地降低了计算机的速率。增设一个联想存储器, 用于保存最近常用的段表项。

  • 分页和分段的主要区别
    页是信息的物理单位,分页是为实现离散分配方式,以消减内存的外零头,提高内存的利用率。仅仅是由于系统管理的需要而不是用户的需要,段则是信息的逻辑单位,它含有一组其意义相对完整的信息。分段的目的是为了能更好地满足用户的需要。

    页的大小固定且由系统决定,由系统把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的,因而在系统中只能有一种大小的页面,而段的长度却不固定,决定于用户所编写的程序,通常由编译程序在对源程序进行编译时,根据信息的性质来划分。

    分页的作业地址空间是一维的,即单一的线性地址空间,程序员只需利用一个记忆符,即可表示一个地址,分段的作业地址空间则是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。

信息共享

  • 在分段系统中,由于是以段为基本单位的,不管该段有多大,我们都只需为该段设置一个段表项,因此使实现共享变得非常容易。

  • 可重入代码(Reentrant Code)
    又称为“纯代码”(Pure Code),是一种允许多个进程同时访问的代码,为使各个进程所执行的代码完全相同,绝对不允许可重入代码在执行中有任何改变。因此,可重入代码是一种不允许任何进程对它进行修改的代码。为此,在每个进程中,都必须配以局部数据区,把在执行中可能改变的部分拷贝到该数据区。这样,程序在执行时,只需对该数据区(属于该进程私有)中的内容进行修改,并不去改变共享的代码。

段页式存储管理方式

  • 基本原理
    先将程序分成若干个段,再把每个段分成若干个页,并为每一个段赋予一个段名。
    地址由段号、段内页号及页内地址三部分所组成。

    在段页式系统中,为了实现从逻辑地址到物理地址的变换,系统中需要同时配置段表和页表,段表的内容与分段系统略有不同,它不再是内存始址和段长,而是页表始址和页表长度。

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

    在段页式系统中,为了获得一条指令或数据,须三次访问内存。第一次访问是访问内存中的段表,从中取得页表始址,第二次访问是访问内存中的页表,从中取出该页所在的物理块号,并将该块号与页内地址一起形成指令或数据的物理地址。第三次访问才是真正从第二次访问所得的地址中,取出指令或数据。

    为了提高执行速度,在地址变换机构中增设一个高速缓冲寄存器。每次访问它时,都须同时利用段号和页号去检索高速缓存。若找到匹配的表项,便可从中得到相应页的物理块号,用来与页内地址一起形成物理地址,若未找到匹配表项,则仍须再三次访问内存。

虚拟存储器的基本概念

虚拟存储器的引入

  • 之前所介绍的各种存储器管理方式都要求将一个作业全部装入内存后方能运行。于是,出现了下面这样两种情况:有的作业很大,其所要求的内存空间超过了内存总容量,作业不能全部被装入内存,致使该作业无法运行。有大量作业要求运行,但内存容量不足以容纳所有这些作业,只能将少数作业装入内存让它们先运行,而将其它大量的作业留在外存上等待。

  • 常规存储器管理方式的特征
    一次性:作业在运行前需一次性地全部装入内存,有许多作业在每次运行时,并非其全部程序和数据都要用到,如果一次性地装入其全部程序,也是一种对内存空间的浪费。

    驻留性:作业装入内存后,便一直驻留在内存中,直至作业运行结束。

  • 局部性原理
    即在一较短的时间内(时间局限性),程序的执行仅局限于某个部分,相应地,它所访问的存储空间也局限于某个区域(空间局限性)。

    时间局限性:如果程序中的某条指令一旦执行,则不久以后该指令可能再次执行,如果某数据被访问过,则不久以后该数据可能再次被访问。产生时间局限性的典型原因是由于在程序中存在着大量的循环操作

    空间局限性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,其典型情况便是程序的顺序执行。

  • 虚拟存储器的定义
    指具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统
    其逻辑容量由内存容量和外存容量之和所决定,其运行速度接近于内存速度,而每位的成本却又接近于外存。

虚拟存储器的特征

  • 多次性
    多次性是指一个作业被分成多次调入内存运行,亦即在作业运行时没有必要将其全部装入,只需将当前要运行的那部分程序和数据装入内存即可,以后每当要运行到尚未调入的那部分程序时,再将它调入。

  • 对换性
    即在进程运行期间,允许将那些暂不使用的程序和数据,从内存调至外存的对换区(换出)。待以后需要时再将它们从外存调至内存(换进),甚至还允许将暂时不运行的进程调至外存,待它们又具备运行条件时再调入内存

  • 虚拟性
    虚拟性是指能够从逻辑上扩充内存容量,使用户所看到的内存容量远大于实际内存容量。

请求分页存储管理方式

  • 这是在分页系统的基础上,增加了请求调页功能页面置换功能所形成的页式虚拟存储系统,它允许只装入少数页面的程序(及数据),便启动运行。以后,再通过调页功能及页面置换功能,陆续地把即将要运行的页面调入内存,同时把暂不运行的页面换出到外存上。置换时以页面为单位。
  • 为了能实现请求调页和置换功能,系统必须提供必要的硬件支持和相应的软件。

请求分页中的硬件支持

  • 请求分页的页表机制
    它是在纯分页的页表机制上增加若干项而形成的,作为请求分页的数据结构,其基本作用仍然是将用户地址空间中的逻辑地址映射为内存空间中的物理地址。

  • 为了满足页面换进换出的需要,在请求页表中又增加了四个字段:页号,物理块号,状态位P,访问字段A,外存地址。

    状态位 P:用于指示该页是否已调入内存

    访问字段 A:用于记录本页在一段时间内被访问的次数,或记录本页最近已有多长时间未被访问。

    修改位 M:表示该页在调入内存后是否被修改过。若未被修改,在置换该页时就不需再将该页写回到外存上,以减少系统的开销和启动磁盘的次数。若已被修改,则必须将该页重写到外存上,以保证外存中所保留的始终是最新副本。

    外存地址:用于指出该页在外存上的地址,通常是物理块号。

  • 缺页中断机构
    每当用户程序要访问的页面尚未调入内存时,便产生一缺页中断,以请求 OS 将所缺的页调入内存,缺页中断作为中断,它们同样需要经历诸如保护 CPU 环境、分析中断原因、转入缺页中断处理程、恢复 CPU 环境等。但缺页中断又是一种特殊的中断,它与一般的中断相比,有着明显的区别,主要表现在下面两个方面:

    在指令执行期间产生和处理中断信号:通常,CPU 都是在一条指令执行完后,才检查是否有中断请求到达,若有,便去响应,否则,继续执行下一条指令。然而,缺页中断是在指令执行期间,发现所要访问的指令或数据不在内存时所产生和处理的。

    一条指令在执行期间,可能产生多次缺页中断

    基于这些特征,系统中的硬件机构应能保存多次中断时的状态,并保证能返回到产生缺页中断的指令处继续执行

  • 地址变换机构
    在进行地址变换时,首先去检索快表,试图从中找出所要访问的页。若找到,便修改页表项中的访问位。对于写指令,还须将修改位置成“1”,然后利用页表项中给出的物理块号和页内地址形成物理地址,地址变换过程到此结束。如果在快表中未找到该页的页表项时,应到内存中去查找页,再从找到的页表项中的状态位 P,来了解该页是否已调入内存。若该页已调入内存,这时应将此页的页表项写入快表,当快表已满时,应先调出按某种算法所确定的页的页表项,然后再写入该页的页表项,若该页尚未调入内存,这时应产生缺页中断,请求OS 从外存把该页调入内存。

  • 实现请求分页的软件
    这里包括有用于实现请求调页的软件和实现页面置换的软件。它们在硬件的支持下,将程序正在运行时所需的页面调入内存,再将内存中暂时不用的页面从内存置换到磁盘上 。

内存分配策略和分配算法

  • 最小物理块数的确定
    指能保证进程正常运行所需的最小物理块数。随着为每个进程所分配的物理块的减少,将使进程在执行中的缺页率上升,从而会降低进程的执行速度。

  • 内存分配策略
    在请求分页系统中,可采取两种内存分配策略,即固定和可变分配策略。在进行置换时,也可采取两种策略,即全局置换和局部置换。

    固定分配局部置换(Fixed Allocation,Local Replacement)
    这是指基于进程的类型(交互型或批处理型等),或根据程序员、程序管理员的建议,为每个进程分配一定数目的物理块,在整个运行期间都不再改变。如果进程在运行中发现缺页,则只能从该进程在内存的 n 个页面中选出一个页换出,然后再调入一页,以保证分配给该进程的内存空间不变。实现这种策略的困难在于:应为每个进程分配多少个物理块难以确定。

    可变分配全局置换(Variable Allocation,Global Replacement)
    这可能是最易于实现的一种物理块分配和置换策略。在采用这种策略时,先为系统中的每个进程分配一定数目的物理块,而OS 自身也保持一个空闲物理块队列。当某进程发现缺页时,由系统从空闲物理块队列中取出一个物理块分配给该进程,并将欲调入的(缺)页装入其中。这样,凡产生缺页(中断)的进程,都将获得新的物理块。仅当空闲物理块队列中的物理块用完时,OS 才能从内存中选择一页调出,该页可能是系统中任一进程的页。这样,自然又会使那个进程的物理块减少,进而使其缺页率增加。

    可变分配局部置换(Variable Allocation,Local Replacement)
    这是基于进程的类型或根据程序员的要求,为每个进程分配一定数目的物理块。当某进程发现缺页时,只允许从该进程在内存的页面中选出一页换出,这样就不会影响其它进程的运行。如果进程在运行中频繁地发生缺页中断,则系统须再为该进程分配若干附加的物理块,直至该进程的缺页率减少到适当程度为止;反之,若一个进程在运行过程中的缺页率特别低,则此时可适当减少分配给该进程的物理块数,但不应引起其缺页率的明显增加。

  • 物理块分配算法
    平均分配算法:即将系统中所有可供分配的物理块平均分配给各个进程。

    按比例分配算法:即根据进程的大小按比例分配物理块。

    考虑优先权的分配算法:把内存中可供分配的所有物理块分成两部分,一部分按比例地分配给各进程;另一部分则根据各进程的优先权进行分配,为高优先进程适当地增加其相应份额。在有的系统中,如重要的实时控制系统,则可能是完全按优先权为各进程分配其物理块的。

调页策略

为使进程能够正常运行,必须事先将要执行的那部分程序和数据所在的页面调入内存。

  • 调入页面的时机
    预调页策略 :如果进程的许多页是存放在外存的一个连续区域中,则一次调入若干个相邻的页,会比一次调入一页更高效些。但如果调入的一批页面中的大多数都未被访问,则又是低效的。 可采用一种以预测为基础的预调页策略,将那些预计在不久之后便会被访问的页面预先调入内存。这种策略主要用于进程的首次调入时,由程序员指出应该先调入哪些页。

    请求调页策略 :当进程在运行中需要访问某部分程序和数据时,若发现其所在的页面不在内存,便立即提出请求,由 OS 将其所需页面调入内存。由请求调页策略所确定调入的页,是一定会被访问的,但这种策略每次仅调入一页,故须花费较大的系统开销,增加了磁盘 I/O 的启动频率。

  • 确定从何处调入页面
    请求分页系统中的外存分为两部分:用于存放文件的文件区和用于存放对换页面的对换区。通常,由于对换区是采用连续分配方式,而文件区是采用离散分配方式,故对换区的磁盘 I/O 速度比文件区的高。这样,每当发生缺页请求时,系统应从何处将缺页调入内存,可分成如下三种情况:

    系统拥有足够的对换区空间,这时可以全部从对换区调入所需页面,以提高调页速度。为此,在进程运行前,便须将与该进程有关的文件从文件区拷贝到对换区。

    系统缺少足够的对换区空间,这时凡是不会被修改的文件都直接从文件区调入;而换出这些页面时,由于它们未被修改而不必再将它们换出,以后再调入时,仍从文件区直接调入。但对于那些可能被修改的部分,在将它们换出时,便须调到对换区,以后需要时,再从对换区调入。

    UNIX 方式。由于与进程有关的文件都放在文件区,故凡是未运行过的页面,都应从文件区调入。而对于曾经运行过但又被换出的页面,由于是被放在对换区,因此在下次调入时,应从对换区调入。由于 UNIX 系统允许页面共享,因此,某进程所请求的页面有可能已被其它进程调入内存,此时也就无须再从对换区调入。

  • 页面调入过程
    每当程序所要访问的页面未在内存时,便向 CPU 发出一缺页中断。中断处理程序首先保留 CPU 环境,分析中断原因后转入缺页中断处理程序。该程序通过查找页表,得到该页在外存的物理块后,如果此时内存能容纳新页,则启动磁盘 I/O 将所缺之页调入内存,然后修改页表。如果内存已满,则须先按照某种置换算法从内存中选出一页准备换出;如果该页未被修改过,可不必将该页写回磁盘;但如果此页已被修改,则必须将它写回磁盘,然后再把所缺的页调入内存,并修改页表中的相应表项,并将此页表项写入快表中。在缺页调入内存后,利用修改后的页表,去形成所要访问数据的物理地址, 再去访问内存数据。整个页面的调入过程对用户是透明的。

页面置换算法

  • 影响页面换进换出效率的若干因素
    页面置换算法。
    写回磁盘的频率。
    读入内存的频率

  • 访问内存的有效时间
    在请求分页管理方式中,内存有效访问时间不仅要考虑访问页表和访问实际物理地址数据的时间,还必须要考虑到缺页中断的处理时间。

  • 缺页率
    假设一个进程的逻辑空间为n页,系统为其分配的内存物理块数为m(m≤n)。如果在进程的运行过程中,访问页面成功(即所访问页面在内存中)的次数为S,访问页面失败(即所访问页面不在内存中,需要从外存调入)的次数为F,则该进程总的页面访问次数为A = S + F,那么该进程在其运行过程中的缺页率为f=F/A。

    事实上,在缺页中断处理时,当由于空间不足,需要置换部分页面到外存时,选择被置换页面还需要考虑到置换的代价。如页面是否被修改过:没有修改过的页面可以直接放弃,而修改过的页面则必须进行保存,所以处理这两种情况时的时间也是不同的。

    假设被置换的页面被修改的概率是β,其缺页中断处理时间为ta,被置换页面没有被修改的缺页中断时间为tb,那么,缺页中断处理时间的计算公式为t=β×ta+(1—β)×tb。

  • 产生“抖动”的原因
    根本原因是,同时在系统中运行的进程太多,由此分配给每一个进程的物理块太少,不能满足进程正常运行的基本要求,致使每个进程在运行时,频繁地出现缺页,必须请求系统将所缺之页调入内存,这会使得在系统中排队等待页面调进/调出的进程数目增加,显然,对磁盘的有效访问时间也随之急剧增加,造成每个进程的大部分时间都用于页面的换进/换出,而几乎不能再去做任何有效的工作,从而导致发生处理机的利用率急剧下降并趋于0的情况。

    进程发生缺页率的时间间隔与进程所获得的物理块数有关。

  • 工作集
    是指在某段时间间隔里,进程实际所要访问页面的集合,虽然程序只需要少量的几页在内存便可运行,但为了较少地产生缺页,应将程序的全部工作集装入内存中,然而我们无法事先预知程序在不同时刻将访问哪些页面,故只有用程序的过去某段时间内的行为作为程序在将来某段时间内行为的近似。

  • “抖动”的预防方法
    在页面分配和置换策略中,如果采取的是可变分配方式,则为了预防发生“抖动”,可采取局部置换策略。

    把工作集算法融入到处理机调度中,当调度程序发现处理机利用率低下时,它将试图从外存调入一个新作业进入内存,来改善处理机的利用率。

    利用“L=S”准则调节缺页率:其中L是缺页之间的平均时间,S是平均缺页服务时间,即用于置换一个页面所需的时间,如果是L远比S大,说明很少发生缺页,磁盘的能力尚未得到充分的利用。如果是L比S小,则说明频繁发生缺页,缺页的速度已超过磁盘的处理能力。只有当L与S接近时,磁盘和处理机都可达到它们的最大利用率。

    选择暂停的进程:当多道程序度偏高时,已影响到处理机的利用率,为了防止发生“抖动”,系统必须减少多道程序的数目。

最佳置换算法和先进先出置换算法

  • 最佳(Optimal)置换算法
    一种理想化的算法,它具有最好的性能,但实际上却难于实现,所选择的被淘汰页面将是以后永不使用的,或许是在最长(未来)时间内不再被访问的页面。采用最佳置换算法通常可保证获得最低的缺页率。

    由于人们目前还无法预知,一个进程在内存的若干个页面中,哪一个页面是未来最长时间内不再被访问的。因而该算法是无法实现的,但可以利用该算法去评价其它算法。

  • 先进先出(FIFO)页面置换算法
    直观的算法,可能是性能最差。FIFO算法是最早出现的置换算法。该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。

    算法实现简单,只需把一个进程已调入内存的页面按先后次序链接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的页面。该算法与进程实际运行的规律不相适应,因为在进程中,有些页面经常被访问 FIFO算法并不能保证这些页面不被淘汰。

最近最久未使用(LRU)置换算法

  • 选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间t。当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最久未使用的页面予以淘汰。

  • 硬件支持
    寄存器:为了记录某进程在内存中各页的使用情况,须为每个在内存中的页面配置一个移位寄存器,可表示为R = Rn-1Rn-2Rn-3 … R2R1R0。当进程访问某物理块时,要将相应寄存器的Rn-1位置成1。此时,定时信号将每隔一定时间(例如100 ms)将寄存器右移一位。如果我们把n位寄存器的数看作是一个整数,那么具有最小数值的寄存器所对应的页面,就是最近最久未使用的页面。

    栈:可利用一个特殊的栈保存当前使用的各个页面的页面号,每当进程访问某页面时,便将该页面的页面号从栈中移出,将它压入栈顶。因此,栈顶始终是最新被访问页面的编号,而栈底则是最近最久未使用页面的页面号。

Clock 置换算法

  • 简单的 Clock 置换算法
    为每页设置一位访问位,再将内存中的所有页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位被置 1。

    置换算法在选择一页淘汰时,只需检查页的访问位。如果是 0,就选择该页换出;若为 1,则重新将它置 0,暂不换出,再按照 FIFO 算法检查下一个页面。当检查到队列中的最后一个页面时,若其访问位仍为 1,则再返回到队首去检查第一个页面。

  • 改进型 Clock 置换算法
    在将一个页面换出时,如果该页已被修改过,便须将该页重新写回到磁盘上;但如果该页未被修改过,则不必将它拷回磁盘。

    在改进型 Clock 算法中,除须考虑页面的使用情况外,还须再增加一个因素,即置换代价。选择页面换出时,既要是未使用过的页面,又要是未被修改过的页面。把同时满足这两个条件的页面作为首选淘汰的页面。

    从当前位置开始,扫描循环队列,寻找 A(访问位)=0且 M(修改位)=0 的第一类页面,将所遇到的第一个页面作为所选中的淘汰页。在第一次扫描期间不改变访问位 A。 如果查找一周后未遇到第一类页面,则开始第二轮扫描,寻找 A=0 且 M=1 的第二类页面。将所遇到的第一个这类页面作为淘汰页。在第二轮扫描期间,将所有扫描过的页面的访问位都置 0。如果未找到第二类页面,则将指针返回到开始的位置,并将所有的访问位复 0。然后重复第一步,如果仍失败,必要时再重复第二步,此时就一定能找到被淘汰的页。

    算法与简单 Clock 算法比较,可减少磁盘的 I/O 操作次数。但为了找到一个可置换的页,可能须经过几轮扫描。换言之,实现该算法本身的开销将有所增加。

其它置换算法

  • 最少使用(Least Frequently Used,LFU)置换算法
    在采用LFU算法时,应为在内存中的每个页面设置一个移位寄存器,用来记录该页面被访问的频率,该置换算法选择在最近时期使用最少的页面作为淘汰页。

  • 页面缓冲算法(PBA:Page Buffering Algorithm)
    该算法规定将一个被淘汰的页放入两个链表中的一个。如果页面未被修改,就将它直接放入空闲链表中;否则,便放入已修改页面的链表中。须注意的是,这时页面在内存中并不做物理上的移动,而只是将页表中的表项移到上述两个链表之一中。

    空闲页面链表,实际上是一个空闲物理块链表,其中的每个物理块都是空闲的,因此,可在其中装入程序或数据。当需要读入一个页面时,便可利用空闲物理块链表中的第一个物理块来装入该页。当有一个未被修改的页要换出时,实际上并不将它换出内存,而是把该未被修改的页所在的物理块挂在自由页链表的末尾。类似地,在置换一个已修改的页面时,也将其所在的物理块挂在修改页面链表的末尾。

    利用这种方式可使已被修改的页面和未被修改的页面都仍然保留在内存中。当该进程以后再次访问这些页面时,只需花费较小的开销,使这些页面又返回到该进程的驻留集中。当被修改的页面数目达到一定值时,再将它们一起写回到磁盘上,从而显著地减少了磁盘 I/O 的操作次数。

请求分段存储管理方式

这是在分段系统的基础上,增加了请求调段及分段置换功能后所形成的段式虚拟存储系统。它允许只装入少数段(而非所有的段)的用户程序和数据,即可启动运行。以后再通过调段功能和段的置换功能将暂不运行的段调出,同时调入即将运行的段。置换以段为单位进行。

请求分段中的硬件支持

  • 请求分段的段表机制:
    在请求分段式管理中所需的主要数据结构是请求段表。在该表中除了具有请求分页机制中有的访问字段A、修改位M、存在位P和外存始址四个字段外,还增加了存取方式字段和增补位:段名,段长,段基址, 存取方式,访问字段A,修改位M,存在位,增补位,外存始址。

    存取方式:用于标识本分段的存取属性是只执行、只读,还是允许读/写。

    访问字段 A:用于记录该段被访问的频繁程度。

    修改位 M:用于表示该页在进入内存后是否已被修改。

    存在位 P:指示本段是否已调入内存。

    增补位:这是请求分段式管理中所特有的字段,用于表示本段在运行过程中是否做过动态增长。

    外存始址:指示本段在外存中的起始地址,即起始盘块号。

  • 缺页中断机构
    在请求分段系统中采用的是请求调段策略,每当发现运行进程所要访问的段尚未调入内存时,便由缺段中断机构产生一缺段中断信号。由缺段中断处理程序将所需的段调入内存。

    需要在一条指令的执行期间产生和处理中断,以及在一条指令执行期间,可能产生多次缺段中断。

    但由于分段是信息的逻辑单位,因而不可能出现一条指令被分割在两个分段中,和一组信息被分割在两个分段中的情况。

  • 地址变换机构:
    请求分段系统中的地址变换机构是在分段系统地址变换机构的基础上形成的,因为被访问的段并非全在内存,所以在地址变换时,若发现所要访问的段不在内存,必须先将所缺的段调入内存,并修改段表,然后才能再利用段表进行地址变换,为此,在地址变换机构中又增加了某些功能,如缺段中断的请求及处理等。

分段的共享

  • 共享段表
    为了实现分段共享,可在系统中配置一张共享段表,所有各共享段都在共享段表中占有一表项。表项中记录了共享段的段号、段长、内存始址、存在位等信息,并记录了共享此分段的每个进程的情况。

  • 共享进程计数 count
    非共享段仅为一个进程所需要。当进程不再需要该段时,可立即释放该段,并由系统回收该段所占用的空间。而共享段是为多个进程所需要的,当某进程不再需要而释放它时,系统并不回收该段所占内存区,仅当所有共享该段的进程全都不再需要它时,才由系统回收该段所占内存区。为了记录有多少个进程需要共享该分段,设置了一个整型变量 count。

  • 存取控制字段。
    对于一个共享段,应给不同的进程以不同的存取权限

  • 段号
    对于一个共享段,不同的进程可以各用不同的段号去共享该段

  • 共享段的分配
    在为共享段分配内存时,对第一个请求使用该共享段的进程,由系统为该共享段分配一物理区,再把共享段调入该区,同时将该区的始址填入请求进程的段表的相应项中。还须在共享段表中增加一表项,填写有关数据,把 count 置为 1;之后,当又有其它进程需要调用该共享段时,由于该共享段已被调入内存,故此时无须再为该段分配内存,而只需在调用进程的段表中增加一表项,填写该共享段的物理地址;在共享段的表中,填上调用进程的进程名、存取控制等,再执行 count :=count+1 操作,以表明有两个进程共享该段。

  • 共享段的回收
    当共享此段的某进程不再需要该段时,应将该段释放,包括撤消在该进程段表中共享段所对应的表项,以及执行 count :=count-1 操作。若结果为 0,则须由系统回收该共享段的物理内存,以及取消在共享段表中该段所对应的表项,表明此时已没有进程使用该段;否则,只是取消调用者进程在共享段表中的有关记录。

  • 分段保护:
    越界检查
    在段表寄存器中放有段表长度信息;同样,在段表中也为每个段设置有段长字段。在进行存储访问时,首先将逻辑地址空间的段号与段表长度进行比较,如果段号等于或大于段表长度,将发出地址越界中断信号,其次,还要检查段内地址是否等于或大于段长,若大于段长,将产生地址越界中断信号,从而保证了每个进程只能在自己的地址空间内运行。

    存取控制检查
    在段表的每个表项中,都设置了一个“存取控制”字段,用于规定对该段的访问方式。

    环保护机构
    这是一种功能较完善的保护机制。在该机制中规定:低编号的环具有高优先权。OS 核心处于 0 环内;某些重要的实用程序和操作系统服务占居中间环;而一般的应用程序则被安排在外环上。在环系统中,程序的访问和调用应遵循以下规则: 一个程序可以访问驻留在相同环或较低特权环中的数据,一个程序可以调用驻留在相同环或较高特权环中的服务。

发布了30 篇原创文章 · 获赞 1 · 访问量 395

猜你喜欢

转载自blog.csdn.net/weixin_46265246/article/details/105227577