操作系统中的存储管理

存储模型

  • 1 地址重定位
  • 2 物理内存管理
  • 3 基本的内存管理方案
  • 4 交换技术(Swapping)
  • 5 虚拟存储技术
  • 6 虚拟页式存储方案
  • 7 虚拟存储方案中的软件策略
  • 8 页面置换算法
  • 9 常见相关问题

1 地址重定位

地址重定位是在存储模型中非常重要的概念,也叫做地址转换、地址映射、地址翻译。在讲解地址重定位之前,需要知道以下知识:

  • 程序装载到内存才可以运行,通常程序以可执行文件格式保存在磁盘上
  • 多道程序设计模型中允许多个程序同时进入内存,在内存中不同的进程都会占据一部分空间
  • 每个进程有自己的地址空间,一个进程执行时不能访问另一个进程的地址空间,进程不能对内存执行不适合的操作

在存储模型中需要解决的问题?进程有自己的地址空间,进程要执行必须要装载进内存才能执行,对于多道程序设计模型,多个进程都要装载进物理内存中,每个进程都需要占据物理内存中的一部分空间,因此在存储模型中需要解决如何把进程地址空间的内容装载进物理内存中,使每个进程正确运行。

进程地址空间
进程地址空间通常一分为二:内核地址空间和用户地址空间,其中用户地址空间包含进程的代码和数据,以及在运行过程中可能扩展的堆和栈,还有一部分空间用来存放共享库、内存映射文件等其他内容。如下图所示是linux进程地址空间的布局
操作系统中的存储管理_第1张图片
通过以上分析可以知道:进程中的地址不是最终的物理地址,在进程运行前无法计算出物理地址,因此需要一种机制实现进程地址空间向物理地址的转换,从而将进程加载进内存执行,即需要地址重定位机制的支持。

地址重定位
这个概念涉及到逻辑地址到物理地址的转换

  • 逻辑地址(相对地址、虚拟地址):用户程序经过编译、汇编后形成目标代码,目标代码通常采用相对地址的形式,其首地址为0,其余地址都相对于首地址而编址,不能用逻辑地址在内存中读取信息
  • 物理地址(绝对地址,实地址):内存中存储单元的地址,可直接寻址,处理器可以直接从物理内存中取得指令和数据

为了保证CPU执行指令时可正确访问内存单元,需要将用户程序中的逻辑地址转换为运行时可由机器直接寻址的物理地址,这一过程称为地址重定位。

地址重定位的方式

  • 静态重定位: 当用户程序加载到内存时,一次性实现逻辑地址到物理地址的转换,一般可以由软件完成。优点是程序的执行过程中可以直接使用物理地址寻址,但是程序在内存中的位置不会改变,一旦改变就需要重新计算物理地址才能运行。
  • 动态重定位:程序在装载进内存之后不会立即将逻辑地址转换为物理地址,而是在进程执行过程中进行地址变换,即逐条指令执行时完成地址转换,需要硬件部件支持。这是经常使用的重定位方式,因为程序在执行过程中位置要进程改变,一个进程可能被多次换出内存,又被多次换入,而每次换入后的位置通常是不同的。

如下图所示,当一个进程加载进内存之后就知道该进程在物理内存的首地址,假设为12000,将物理内存的首地址写入重定位寄存器,CPU取到进程的逻辑地址假设为456,经过内存管理单元(MMU)完成地址转换的工作,得到进程在内存的物理地址,CPU根据物理地址取得指令和数据。
操作系统中的存储管理_第2张图片

2 物理内存管理

空闲物理内存管理
对物理内存可以有不同的划分,可以是等长划分,即把一片空闲的物理内存划分为等长的区域,每个区域称为一个分配单元,某个进程进内存的时候可能分配若干了分配单元满足进程对内存的需求;第二种划分是不等长划分。需要不同的数据结构来管理物理内存。
操作系统中的存储管理_第3张图片

等长划分可以使用位图这种数据结构:每个分配单元对应于位图中的一位,0表示空闲,1表示占用(或者相反)。
不等长划分可以使用空闲区表、已分配区表这种数据结构:表中每一项记录了空闲区(或已分配区)的起始地址、长度、标志,也可以使用空闲块链表来表示。

内存分配算法及回收

  • 首次适配 first fit:在空闲区表中找到第一个满足进程要求的空闲区
  • 下次适配 next fit:从上次找到的空闲区处接着查找
  • 最佳适配 best fit:查找整个空闲区表,找到能够满足进程要求的最小空闲区
  • 最差适配 worst fit:总是分配满足进程要求的最大空闲区

内存分配算法将该空闲区分为两部分,一部分供进程使用,另一部分形成新的空闲区;内存回收算
当某一块归还后,前后空闲空间合并,修改内存空闲区表。

伙伴系统
Linux低层内存管理采用的内存分配方案,主要思想是将内存按2的幂进行划分,组成若干空闲块链表;查找该链表找到能满足进程需求的最佳匹配块。 算法设计如下:

(1)首先将整个可用空间看作一块: 2^U
(2)假设进程申请的空间大小为s,如果满足2^U-1

3 基本的内存管理方案

首先介绍单一连续区、固定分区、可变分区这三种内存管理方案,特点是整个进程进入内存中一块连续的区域。

(1)单一连续区
在单道程序环境下,当时的内存管理方式是把内存分为系统区和用户区两部分,在用户区内存中,仅装有一道用户程序,即整个内存的用户空间被改程序独占。特点是一段时间内只有一个进程在内存,简单但是内存利用率低

(2)固定分区
把内存空间分割成若干区域,称为分区,其中每个分区的大小可以相同也可以不同,每个分区一旦确定分区的大小就不会改变,每个分区装一个且只能装一个进程。
操作系统中的存储管理_第4张图片
(3)可变分区
根据进程的需要,把内存空闲空间分割出一个分区,分配给该进程,剩余部分成为新的空闲区。但是这种分区方式会产生较多的外碎片(指两个进程占据内存空间之间少量的空闲内存空间),导致内存利用率下降。

碎片是指很小的、不易利用的空闲区,会导致内存利用率下降。可以利用紧缩技术(memory compaction)来解决碎片问题,在内存移动程序,将所有小的空闲区合并为较大的空闲区,又称为压缩技术,紧致技术,搬家技术。在解决碎片的时候需要注意对内存进行压缩可能会造成时间和空间的开销,另一方面不是所有的进程都可以执行紧缩技术,例如一个进程正在执行I/O操作时就不能移动进程,否则会造成I/O结果错误。

接下来介绍另外三种内存管理方案:段式、页式和段页式,特点是一个进程进入内存中若干个不连续的区域。

(4)页式存储方案
设计思想:用户进程地址空间被划分为大小相等的部分,称为页(page)或页面,从0开始编号;内存空间按同样大小划分为大小相等的区域,称为页框(page frame),从0开始编号,也称为物理页面,页帧,内存块。以页为单位进行分配,并按进程需要的页数来分配;逻辑上相邻的页,物理上不一定相邻

逻辑地址在页式存储方案中由两部分组成:页号和页内地址(位偏移),这个划分是由系统自动完成的。
操作系统中的存储管理_第5张图片
内存分配过程
如图所示,逻辑上相邻的地址在物理位置上不一定相邻,需要思考一个问题:程序在执行的时候,不考虑跳转情况的话程序是按照顺序执行的,如果执行玩上一页的最后一条指令,然后去执行下一页的第一条指令,如何找到下一页的页框?这时候就需要引入页表这个概念,把逻辑上的某一页和物理上的某一页框的对应关系记录下来。
操作系统中的存储管理_第6张图片
相关数据结构以及地址转换
在页式存储方案中,最重要的数据结构就是页表,页表由若干个页表项组成,页表项记录了逻辑页号与页框号的对应关系,每个进程一个页表,存放在内存。

地址转换过程需要硬件支持,CPU取到逻辑地址,自动划分为页号和页内地址;用页号查页表,得到页框号,再与页内偏移拼接成为物理地址。

在页式存储方案是会产生内碎片问题,例如一个进程需要五页再加一条指令,那么该进程实际上会配分配六页物理内存,如果最后一条指令只在最后一页上占据了很少的空间,那么这一页就会的大部分都是空的,造成浪费。

(5)段式存储方案
设计思想:用户进程地址空间是按程序自身的逻辑关系划分为若干个程序段,每个程序段都有一个段名;内存空间被动态划分为若干长度不相同的区域,称为物理段,每个物理段由起始地址和长度确定。内存分配规则是以段为单位进行分配,每段在内存中占据连续空间,但各段之间可以不相邻。

逻辑地址也由两部分组成:段号以及段内地址(段偏移),与页式存储方案不同的是,段号和段内地址不是系统自动划分的,必须显式给出。
操作系统中的存储管理_第7张图片
相关数据结构以及地址转换
在段式存储结构中,段表中的每一项都记录了段号、段首地址和段长度之间的关系,每个进程一个段表,存放在内存。

地址转换过程也是由硬件支持的,CPU取到逻辑地址,用段号查段表,得到该段在内存的起始地址,与段内偏移地址计算出物理地址。

(6)段页式存储方案
综合页式、段式方案的优点,克服二者的缺点,设计思想:用户进程的逻辑关系先划分为段,每一段再按页面划分。因此段页式存储方案的逻辑地址实际上由三部分组成:第一部分是段号,原来的段内地址又划分为页号和页内地址。

段页式存储方案的数据结构包含段表和页表。段表记录了每一段的页表始址和页表长度,页表记录了逻辑页号与页框号的对应关系。每一段有一张页表,所以一个进程有多个页表。

基本内存管理方案小结:

内存管理方案 特点
单一连续区 每次只运行一个用户程序,用户程序独占内存,它总是被加载到同一个内存地址上
固定分区 把可分配的内存空间分割成若干个连续区域,每一区域称为分区。每个分区的大小可以相同也可以不同,分区大小固定不变,每个分区装一个且只能装一个进程
可变分区 根据进程的需求,把可分配的内存空间分割出一个分区,分配给该进程
页式 把用户程序地址空间划分成大小相等的部分,称为页。内存空间按页的大小划分为大小相等的区域,称为内存块(物理页面,页框,页帧)。以页为单位进行分配,逻辑上相邻的页,物理上不一定相邻
段式 用户程序地址空间按进程自身的逻辑关系划分为若干段,内存空间被动态的划分为若干个长度不相同的区域(可变分区)。以段为单位分配内存,每一段在内存中占据连续空间,各段之间可以不连续存放
段页式 用户程序地址空间:段式;内存空间:页式;分配单位:页

4 交换技术(Swapping)

交换技术的引入是面对这样一个问题:一个大的进程地址空间如何装载到一个小的可用的物理内存,即内存不足的时候如何进行内存管理。交换技术就是为了解决这个问题,如何在一个较小的内存空间运行较大的进程。

解决这个问题采用的技术是内存“扩充”技术,但不是在物理上扩展内存,而是使用软件技术或者软硬件结合的技术使得大的进程在较小的物理内存上运行。可以使用以下几种方法实现:

  • 内存紧缩技术(例如:可变分区)
  • 覆盖技术 overlaying
  • 交换技术 swapping
  • 虚拟存储技术 virtual memory

覆盖技术
解决程序大小超过物理内存总和的问题,思路是程序执行过程中,程序的不同部分在内存中相互替代。按照其自身的逻辑结构,将那些不会同时执行的程序段共享同一块内存区域,要求程序各模块之间有明确的调用结构。整个过程要求程序员声明覆盖结构,操作系统完成自动覆盖,适用于早期的操作系统。缺点:对用户不透明,增加了用户负担。

交换技术
交换技术是现在使用的虚拟存储技术最初的一个设计思想,演化到现在就变成了虚拟存储技术。设计思想是当内存空间紧张时,系统将内存中某些进程暂时移到外存,把外存中某些进程换进内存,占据前者所占用的区域(进程在内存与磁盘之间的动态调度)。

在交换过程中,交换的主要是在运行时创建或修改的内容,比如栈和堆;一般系统会指定一块特殊的磁盘区域作为交换空间(swap space)用于存放被交换出的进程,包含连续的磁道,一般不通过文件系统而是直接使用底层的磁盘读写操作对其高效访问;进程很少使用或者内存不够或有不够的危险的时候进行交换;不应该换出等待I/O操作的进程。

5 虚拟存储技术

虚拟存储技术是指当进程运行时,先将其一部分装入内存,另一部分暂留在磁盘,当要执行的指令或访问的数据不在内存时,由操作系统自动完成将它们从磁盘调入内存的工作。

引入了虚拟存储技术之后,每个进程的地址空间称为虚拟地址空间,即分配给进程的虚拟内存。在这个虚拟空间的地址称为虚拟地址,即在虚拟内存中指令或数据的位置,该位置可以被访问,仿佛它是内存的一部分。

在了解虚拟内存在哪里之前,首先要了解存储器的层次结构。在计算机系统当中,可以存放信息的存储介质包括了寄存器、高速缓存、内存和磁盘。在这个层次结构中,越往上存储的容量就越小,速度越快,同时成本也越高;越往下存储的容量越大,相应的速度会更慢,但是价格也更便宜。
操作系统中的存储管理_第8张图片
虚拟存储技术实际上建立在存储结构的层次之上,一部分内容在内存,一部分内容在磁盘,整体构成了进程的虚拟地址空间。把内存与磁盘有机地结合起来使用,从而得到一个容量很大的“内存”,即虚存。虚存是对内存的抽象,构建在存储体系之上,由操作系统协调各存储器的使用。虚存提供了一个比物理内存空间大得多的地址空间。虚存的大小受到计算机系统的寻址机制以及磁盘空间中可用空间两个方面的限制。

6 虚拟页式存储方案

把虚拟技术应用到页式存储方案当中得到的就是虚拟页式存储方案,基本思想是:进程开始运行之前,不是装入全部页面,而是装入一个或零个页面;之后,根据进程运行的需要,动态装入其他页面;当内存空间已满,而又需要装入新的页面时,则根据某种算法置换内存中的某个页面,以便装入新的页面。

虚拟页式存储方案通常有两种形式:第一种是请求调页(demand paging),当需要的页面不在内存时才加载进内存;还有一种方式是预先调页(prepaging),提前把某些需要用到的页面调入内存。虚拟页式存储技术或虚拟技术在是操作系统中的资源转换技术,以CPU时间和磁盘空间换取昂贵内存空间。

页表及页表项的设计问题
如下图所以,虚拟地址空间划分为若干个虚拟地址页面,物理地址空间由若干个页框组成,虚拟地址空间的部分页面加载到物理内存,由页表记录哪些页面已经加载进内存。

操作系统中的存储管理_第9张图片
页表是由页表项组成的,在页表项中包含页框号、有效位、访问位、修改位、保护位。通过页框号给出该虚拟页面对应的物理内存实际的物理页面;有效位表示该页是在内存还是在磁盘;当要读取该页或者使用该页的时候,通过硬件将访问位设置为1,表示物理内存中的该页框被访问过;修改位表示此页在内存中是否被修改过,修改过的页需要在以后的某个时机写入磁盘;保护位进行权限的设置,如该页面是否为只读。通常,页表项是硬件设计的。

现代的大多数计算机系统都支持非常大的逻辑地址空间,在这样的环境下,页表就变得非常大,要占用相当大的内存空间,而且页表项是连续的,当难以在内存中找到一块连续的大内存空间时这显然是不合理的,因此可以将页表项在内存空间中不连续存放的方式来解决这个问题,则需要引入页表页的地址索引表 ,即页目录(Page Directory)。因此将一维的页表设计成二维页面,甚至是多级页表,现在大多数计算机系统都是使用多级页面这种结构。

下面介绍一下二级页表的结构。针对于难以找到大的连续内存空间存放页表的问题,可利用将页表进行分页的方法,使每个页面的大小与物理内存块的大小相同,将他们进行编号,然后离散地将各个页面分别存放在不同的物理块中。同样要为离散页表再建立一张页表,称为页目录,每个页目录中记录了页表页面的物理块号。二级页表的示意图如下:
操作系统中的存储管理_第10张图片
同时为了减少页表所占用的内存空间,引入了反转页表的概念。现在的地址转换是从虚拟地址空间出发,计算机硬件利用虚拟地址的页号去查页表,得到相应的页框号,与虚拟地址的页偏移进行拼接得到物理内存中的物理地址,从虚拟地址映射到物理地址的话,每个进程都有一个页表。页表即使不连续存放也会占据很大的内存空间,因此引入反转页表,不从虚拟地址出发,而是从物理地址出发,整个系统建立一张页表,页表项记录进程i的某虚拟地址(虚页号)与页框号的映射关系,需要在页表项中添加进程信息。但是当CPU取到虚拟地址需要进程地址转换的时候,要查找整个页表,一般使用哈希表来解决查找整个页表使性能降低的问题,将虚拟地址的页号部分映射到一个散列值,散列值指向一个反转页表,查找的时候通过对虚拟地址进行哈希找到反转页表对应的页表项,可以通过链地址法来解决哈希冲突问题。

地址转换过程及TLB(快表)引入
由内存管理单元(MMU)完成虚拟地址到物理地址的转换过程,由于页表是存放在内存中的,这使得CPU没取一个数据的时候,至少要进程两次内存访问。第一次是访问内存中的页表,从页表找到对应的页框号,再与页内偏移拼接形成物理地址。第二次访问内存时,才是从第一次所得到的地址中获得所需要的数据(或向此数据中写入数据)。又由于CPU的指令处理速度与内存指令的访问速度差异大,CPU的速度得不到充分利用。
操作系统中的存储管理_第11张图片

针对以上问题,为了加快地址转换,在地址转换过程中增加了一个具有并行查询能力的特殊的高速缓冲寄存器,又称为“联想寄存器”,或称为“快表”。CPU根据逻辑地址得到页号以后,与高速缓冲区的所有页号进行比较,若其中有与此相匹配的页号,则可以直接在快表中读出该页的页框号可以直接出物理地址;如果没有命中,则去内存中查页表,找到对应的页表项,如果有效位为1表示页面已经加载进内存,通过拼接得到物理地址,如果有效位为0表示页面还没有加载进内存,就会产生缺页异常,控制权转入操作系统,操作系统就将磁盘上的相应内容调入内存。

由于成本关系,快表不可能做的很大,但是由于程序和数据访问往往带有局部性,快表能取得较好的效果。
操作系统中的存储管理_第12张图片
页错误、页故障(Page Fault)
页错误又称 页面错误、页故障、页面失效,通常是指地址转换过程中硬件产生的异常,产生这个异常的具体原因有:所访问的虚拟页面没有调入物理内存,称为缺页异常;还有可能是页面访问违反权限(读/写、用户/内核);或者错误的访问地址等。

下面介绍一下缺页异常,缺页异常是一种Page Fault。在地址映射过程中,硬件检查页表时发现所要访问的页面不在内存,则产生该异常;产生缺页异常之后,进入操作系统,由操作系统执行缺页异常处理程序:获得磁盘地址,启动磁盘,将该页调入内存。再把新的页面调入内存的时候存在两种可能性:

  • 如果内存中有空闲页框,则分配一个页框,将新调入页装入,并修改页表中相应页表项的有效位及相应的页框号
  • 若内存中没有空闲页框,则要置换内存中某一页框;若该页框内容被修改过,则要将其写回磁盘

7 虚拟存储方案中的软件策略

分配策略
驻留集表示操作系统给每个进程分配的页框数,通常有两种分配页框的策略:

  • 固定分配策略:进程创建时就确定给进程分配多少页框,可以根据进程类型(交互、批处理、应用类)或者基于程序员或系统管理员的需要来确定
  • 可变分配策略:分配给进程的页框数量要根据缺页率评估进程局部性表现来做调整

下图表示缺页率和分配给进程的页框数的关系,缺页率随着给进城所分配的页框数明显的减少,但是当分配的页框数超过某个数量的时候,再为进程增加页框数时缺页率的改善已经不明显。

操作系统中的存储管理_第13张图片

置换问题
当内存已经用完了,没有空闲页框的时候,就需要挑选一些页框置换出内存。在置换的过程中,需要考虑置换范围和置换策略。置换范围是指计划置换页面的集合是局限在产生缺页中断的进程,还是所有进程的页框;置换策略是指在计划置换的页框集合中,选择换出哪一个页。

置换范围又可分为局部置换策略和全局置换策略。局部置换策略是指仅在产生本次缺页的进程的驻留集中选择,全局置换策略是指将内存中所有未锁定的页框都作为置换的候选。结合上面请求分页的分配策略,可以得到三种策略方案:固定分配局部置换,可变分配局部置换以及可变分配全局置换。以可变分配局部置换为例来做说明:当一个新进程装入内存时,给它分配一定数目的页框,然后填满这些页框;当发生一次缺页异常时,从产生缺页异常进程的驻留集中选择一页用于置换;不断重新评估进程的页框分配情况,增加或减少分配给它的页框,以提高整体性能。

置换策略决定置换当前内存中的哪一个页框。所有置换策略的目标都需要达到置换最近最不可能访问的页这个目标。根据局部性原理,最近的访问历史和最近将要访问的模式间存在相关性,因此大多数策略都基于过去的行为来预测将来的行为。但是需要注意的是置换策略设计得越精致、越复杂,实现的软硬件开销就越大。并且在页面置换的过程中存在一个约束条件,即不能置换被锁定的页框。

为什么需要锁定页面呢?由于采用虚拟存储技术,可能要访问的代码还不在内存需要临时调入内存,调入内存的话就要启动磁盘等,造成较大的开销,是的进程运行的时间不确定。要使进程运行时间相对稳定的话就可以将每个页框增加一个锁定位来达到这个目的,通过设置相应的锁定位,不让操作系统将进程使用的页面换出内存,避免产生由交换过程带来的不确定的延迟。需要锁定的有操作系统核心代码、关键数据结构、I/O缓冲区等,在前面将紧缩技术的时候也提到正在进行I/O操作的进程是不能进行移动的,也不能交换出内存,因此应该将其锁定。

清除策略
清除是指从进程的驻留集中收回页框。经过统计分析发现,虚拟页式系统工作的最佳状态:发生缺页异常时,系统中有大量的空闲页框。在系统中保存一定数目的空闲页框供给比使用所有内存并在需要时搜索一个页框进行置换有更好的性能。大部分操作系统都会根据这个结论来设计清除策略,而不是当发生缺页异常的时候,再将需要的页框置换进内存。在linux中,通常会设计一个分页守护进程(paging daemon),多数时间睡眠着,可定期唤醒以检查内存的状态。如果空闲页框过少,分页守护进程通过预定的页面置换算法选择页面换出内存;如果页面装入内存后被修改过,则将它们写回磁盘 ,分页守护进程可保证所有的空闲页框是“干净”的。

可能出现这样一种情况,某个页框是进程驻留集中的一个页框,由于分页守护进程根据某个置换算法选择了这个页框就把该页框中该进程的驻留集中回收了,如果该进程还没有结束,又要使用刚刚被置换出内存的页框,如果该页框还没有被新的内容覆盖,则可将它从空闲页框集合中移出即可恢复该页面。这种技术也称为页面缓冲技术。

页缓冲技术说明
(1)不丢弃置换出的页,将它们放入两个表之一:如果未被修改,则放到空闲页链表中,如果修改了,则放到修改页链表中
(2)被修改的页定期写回磁盘(不是一次只写一个,大大减少I/O操作的数量,从而减少了磁盘访问时间)
(3)被置换的页仍然保留在内存中,一旦进程又要访问该页,可以迅速将它加入该进程的驻留集合(代价很小)

8 页面置换算法

在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。页面置换算法和缓存淘汰策略类似,可以将磁盘看成内存的缓存。在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。

不适当的算法可能会导致进程发生“抖动”(Thrashing),即刚刚被换出的页很快有要被访问,需要将它重新调入,此时又需要再选一页调出;而此刚被调出的页有很快被访问,又需将它调入,频繁的切换页面,以致一个进程在运行中把大部分时间都花费在置换工作上,则称进程发生了“抖动”。

页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。从理论上讲,应将那些以后不再需要访问的页面换出,或者把那些较长时间内不会再访问的页面调出。

最佳页面置换算法(OPT)
最佳页面置换算法(OPT,Optimal replacement algorithm)的设计思想是:置换以后不再需要的或在未来时间不会再访问的页面。由于无法预知在内存中的若干个页面中,哪个页面是未来最长时间不会访问的,因此该算法是无法实现的。但是该算法可以作为一种标准来衡量其他算法的性能。

先进先出页面置换算法(FIFO)
先进先出页面置换算法(FIFO,First In First Out)的设计思想是:选择在内存中驻留时间最长的页并置换,它可以使用页面链表法实现,将链表头置换出去。但是该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。

FIFO页面置换算法会产生异常现象(Belady现象),即:当分配给进程的物理页面数增加时,缺页次数反而增加

第二次机会算法(SRC)
第二次机会算法(SRC)是在先进先出置换算法上的改进,FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改:按照先进先出算法选择某一页面,检查其访问位R,如果为0,说明该页有一段时间没有被访问过,则置换该页;如果为1,则给第二次机会,并将访问位置0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。
操作系统中的存储管理_第14张图片
时钟算法
第二次机会算法在链表头部移除页面并挂接在链表尾部存在性能消耗,使用时钟算法进行改进,时钟算法使用环形链表将页面连接起来,通过移动指针来选择要淘汰的页框。如果指针指向的页框访问位为1,则将访问位置为0,移动指针到下一个位置;如果指针指向的页框的访问位为0就置换进新的页面,该页面的访问位为1,指针继续下移。
操作系统中的存储管理_第15张图片

最近未使用置换算法(NRU)
最近未使用置换算法(NRU,Not Recently Used)的设计思想是:选择在最近一段时间内未使用过的一页并置换。根据页表项中的访问位®和 修改位(M)来决定要置换的页面,当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1,由于每次访问R位都会被设置成1,R为就没有任何信息参考,因此R位需要被定期清零(复位)。发生缺页中断时,操作系统检查R,M,存在下面四种情况:

  • 第1类:无访问,无修改
  • 第2类:无访问,有修改
  • 第3类:有访问,无修改
  • 第4类:有访问,有修改

当发生缺页中断时,NRU 算法随机地从类编号最小的非空类中挑选一个页面将它换出。NRU 优先换出已经被修改的脏页面(R=0,M=1),而不是被频繁使用的干净页面(R=1,M=0)

同样可以对这个算法使用时钟实现,步骤如下:

  • 从指针所指示的当前位置开始,扫描循环队列,寻找R=0,M=0的第一类页面,将所遇到的第一个页面作为淘汰页。在第一次扫描期间不改变访问位R
  • 如果第一步失败,即查找一轮没有遇到第一类页面,就开始第二轮扫描,寻找R=0,M=1的第二类页面,将所遇到的第一个这类页面作为淘汰页。在第二轮扫描期间,将所有扫描过的页面的访问位都置为0
  • 如果第二步失败,指针将回到它的最初位置,并且将集合中所有页框的使用位均置为0。重复第1步,如果没有找到淘汰页,重复第2步。这样将可以找到供置换的页框。

最近最久未使用(LRU)
FIFO置换算法的性能之所以较差,是因为它所依据的条件是各个页面调入内存的时间,而页面调入的先后不能反映页面的使用情况。最近最久未使用的页面置换算法是依据页面调入内存后的使用情况作出决策的。由于无法预测各个页面将来的使用情况,只能利用“最近的过去”作为“最近的将来”的近似,因此LRU算法是选择选择最后一次访问时间距离当前时间最长的一页并置换,即该页面的访问时间距离当前时间最大的页面置换掉,也就是置换出未使用时间最长的一页性能最接近最佳页面置换算法,由于要给每个页面设置一个时间戳记录其使用的时间或者维护一个使用页面的栈,系统的开销较大。

可以使用栈来实现LRU,利用一个特殊的栈保存当前使用的各个页面的页面号,每当进程访问某页面的时候,便将该页面的页面号从栈中移出,将它压入栈顶。因此栈顶始终是最近被访问页面的编号,而栈底则是最近最久未使用页面的页面号。假定现有一个进程,它分为五个页框,所访问页面的页号序列为4,7,0,7,1,0,1,2,1,2,6,则栈中页号的变化情况如下图所示:
操作系统中的存储管理_第16张图片
最近最少未使用(LFU)
前面两种LRU算法虽然在理论上都是可以实现的,但只有非常少的计算机拥有这种硬件。NFU(Not Frequently Used,最近最少使用)的设计思想是选择访问次数最少的页面置换,是LRU的一种软件解决方案,但是与LRU的思想还是不一样的。实现是每个页框一个计数器,初值为0;每次时钟中断时,由操作系统扫描内存中所有的页面,将每个页面的R位(它的值是0或1)加到它的计数器上;当发生缺页中断时,则置换计数器值最小的页面。

老化算法(AGING)
LFU算法虽然和LRU差别较大,但是给后续的算法提供了基础。老化算法是对LFU算法的改进,进一步模拟LRU,计数器在加R前先右移一位,R位加到计数器的最左端。如果页面被访问过,计数器R就加1,但是如果长时间没有别访问过R就会慢慢右移,R的作用越来越小,利用这种思想近似模拟LRU。

为了记录某进程在内存中各页的使用情况,须为每个在内存中的页面配置一个移位寄存器,可表示为R=Rn-1 Rn-2 Rn-3 … R2R1R0,当进程访问某页的时候,要将相应的寄存器Rn-1置为1,定时信号每隔一定时间将寄存器右移一位。如果把n为寄存器的数看做是一个整数,那么具有最小数值的寄存器多对应的页面就是最近最近未使用的页面。

页号\寄存器R R7 R6 R5 R4 R3 R2 R1 R0
1 0 1 0 1 0 0 1 0
2 1 0 1 0 1 1 0 0
3 0 0 0 0 0 1 0 0
4 0 1 1 0 1 0 1 1
5 1 1 0 1 0 1 1 0
6 0 0 1 0 1 0 1 1
7 0 0 0 0 0 1 1 1

如上表所示为某个进程在内存中具有8个页面,为每个内存页面配置一个8位寄存器时LRU访问情况,这时第三个内存页面值的R最小,当发生缺页异常的时候,应该把它置换出去。

工作集算法
影响缺页次数的因素包含页面置换算法、页面本身的大小、程序的编制方法以及分配给进程的页框数量等因素,缺页越多系统的性能就越差,不适当的页面置换算法可能导致进程发生抖动或者颠簸,前面对这个概念也有介绍。即在虚存中,页面在内存与磁盘之间频繁调度,使得调度页面所需的时间比进程实际运行的时间还多,这样导致系统效率急剧下降,这种现象称为颠簸或抖动。

前面介绍了缺页率与分配的页框数之间的关系:W点是平衡点,超过W之后缺页率不会下降很多;小于W点缺页率增加分配的页框数时缺页率会快速下降。工作集置换算法的出发点就是基于这个平衡点W。
操作系统中的存储管理_第17张图片
工作集模型的基本思想:根据程序的局部性原理,一般情况下,进程在一段时间内总是集中访问一些页面,这些页面称为活跃页面,如果分配给一个进程的物理页面数太少了,使该进程所需的活跃页面不能全部装入内存,则进程在运行过程中将频繁发生中断;如果能为进程提供与活跃页面数相等的物理页面数,则可减少缺页中断次数。

工作集是指一个进程当前正在使用的页框集合,也是驻留集的基本思路,工作集是需要随时调整的。需要计算当前的工作集是多少,工作集W(t,Δ)表示该进程在过去的Δ个虚拟时间单位中访问到的页面的集合作为时间t的工作集。工作集的大小取决于访页序列特性,时刻t以及工作集的窗口长度(Δ)。

基于以上的工作集模型,提出的工作集置换算法的基本思想是:找出一个不在工作集中的页面并置换它。设计思想是:每个页表项中有一个字段:记录该页面最后一次被访问的时间;设置一个时间T,起到时间窗口的作用;根据一个页面的访问时间是否落在“当前时间-T”之前或之中决定其在工作集之外还是之内。

置换算法总结:

算法 评价
OPT 不可实现,但可作为基准
NRU LRU的很粗略的近似
FIFO 可能置换出重要的页面
Second Chance 比FIFO有很大的改善
Clock 改善算法的性能
LRU 很优秀,但很难实现
NFU LRU的相对粗略的近似
Aging 非常近似LRU的有效算法
Working set 实现起来开销很大

9 常见相关问题

分页和分段有什么区别(内存管理)
页式存储管理方案将用户进程地址空间和内存空间按同样大小划分为大小相等的区域,以页为单位进行分配,逻辑上相邻的页,物理上不一定相邻,由操作系统硬件完成分页,对用户是透明的;
段式存储管理方案将用户进程地址空间是按程序自身的逻辑关系划分为若干个程序段,内存空间被动态划分为若干长度不相同的区域,内存分配规则是以段为单位进行分配,但各段之间可以不相邻,由于分段需要程序员显式划分每个段,是不透明的。

区别可以从以下几个方面讲述:

  • 目的不同:分页是由于系统管理的需要,它是信息的物理单位,对用户不可见;分段的目的是为了能更好地满足用户的需要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;
  • 大小不同:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;
  • 地址空间不同: 分页是系统行为,用户的地址空间是一维的;分段是用户行为,地址空间是二维的,在标识一个地址时即需要给出段名,还要给出段内地址。
  • 信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制;
  • 内存碎片:页的大小固定,因此可以消除外碎片,但会产生内碎片(一个页可能填充不满);而段式管理由于段的大小可变,在内存分配时不会产生内碎片,但段换入换出时,会产生外碎片。

虚拟内存?
虚拟存储技术是指进程开始运行之前,不是装入全部页面,而是装入一个或零个页面;之后,根据进程运行的需要,动态装入其他页面;当内存空间已满,而又需要装入新的页面时,则根据某种算法置换内存中的某个页面,以便装入新的页面。
可以参考博客虚拟存储这一部分内容

页面置算法有哪些颠簸或“抖动“,答案都可以在博客中找到。

你可能感兴趣的:(操作系统)