3.2 虚拟内存管理
3.2.1 虚拟内存的基本概念
-
传统存储管理方式的特征
- 传统存储管理方式
- 连续分配
- 单一连续分配
- 固定分区分配
- 动态分区分配
- 非连续分配
- 基本分页存储管理
- 基本分段存储管理
- 基本段页式存储管理
- 连续分配
特征:
-
一次性:
作业必须一次性全部装入内存后,才能开始运行
。这会导致两种情况:
- ①当作业很大而不能全部被装入内存时,将使该作业无法运行;
- ②当大量作业要求运行时,由于内存不足以容纳所有作业,只能使少数作业先运行,导致多道程序度的下降。
-
驻留性:作业被装入内存后,就一直驻留在内存中,其任何部分都不会被换出,直至作业运行结束。运行中的进程会因等待IO而被阻塞,可能处于长期等待状态。
由以上分析可知,许多在程序运行中不用或暂时不用的程序(数据)占据了大量的内存空间,而一些需要运行的作业又无法装入运行,显然浪费了宝贵的内存资源。
- 传统存储管理方式
-
局部性原理
快表、页高速缓存及虚拟内存技术都属于高速缓存技术,这个技术所依赖的原理就是局部性原理。
-
时间局部性。
程序中的某条指令一且执行,不久后该指令可能再次执行;某数据被访问过,不久后该数据可能再次被访问。产生的原因是程序中存在着大量的循环操作。
-
空间局部性。
一旦程序访问了某个存储单元,在不久后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式聚存储的。
-
-
虚拟存储器的定义和特征
-
虚拟内存技术的实现
虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。
访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存**(请求调页功能)**
内存空间不够时,将内存中暂时用不到的信息换出到外存**(页面置换功能)**
-
所需要的硬件支持
- 一定容量的内存和外存。
- 页表机制(或段表机制),作为主要的数据结构。
- 中断机构,当用户程序要访问的部分尚未调入内存时,则产生中断。
- 地址变换机构,逻辑地址到物理地址的变换。
-
3.2.2 请求分页管理方式
请求分页系统建立在基本分页系统基础之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。
-
页表机制
请求分页系统在一个作业运行之前不要求全部一次性调入内存,因此在作业的运行过程中,必然会出现要访问的页面不在内存中的情况。因此在请求页表项中增加了 4个字段,如下图所示。
- 状态位P:用于指示该页是否已调入内存,供程序访问时参考。
- 访问字段A:用于记录本页在一段时间内被访问的次数,或记录本页最近已有多长时间未被访问,供置换算法换出页面时参考。
- 修改位M:标识该页在调入内存后是否被修改过,以确定页面置换时是否写回外存。
- 外存地址:用于指出该页在外存上的地址,通常是物理块号,供调入该页时参考。
-
缺页中断机构
在请求分页系统中,每当所要访问的页面不在内存中时,便产生一个缺页中断,请求操作系统将所缺的页调入内存。
-
缺页中断执行过程
- 先将缺页的进程阻塞(调页完成唤醒),
- 若内存中有空闲块,则分配一个块,将要调入的页装入该块,并修改页表中的相应页表项,
- 若此时内存中没有空闲块,则要淘汰某页(若被淘汰页在内存期间被修改过,则要将其写回外存)。
-
缺页中断和一般中断的区别:
- 在指令执行期间而非一条指令执行完后产生和处理中断信号,属于内部异常。
- 一条指令在执行期间,可能产生多次缺页中断。
-
-
地址变换机构
请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,为实现虚拟内存,又增加了某些功能而形成的,如产生和处理缺页中断,及从内存中换出一页的功能等等。
请求分页管理的地址变换过程,如下图所示,红框部分为新增步骤:
①只有“写指令”才需要修改“修改位”。并且,一般来说只需修改快表中的数据,只有要将快表项删除时才需要写回内存中的慢表。这样可以减少访存次数。
②和普通的中断处理一样,缺页中断处理依然需要保留CPU现场。
③需要用某种“页面置换算法”来决定一个换出页面(下节内容)
④换入/换出页面都需要启动慢速的I/O操作,可见,如果换入换出太频繁,会有很大的开销。
⑤页面调入内存后,需要修改慢表,同时也需要将表项复制到快表中。
注:只有写指令才需要修改"修改位"
3.2.3 页框分配
-
驻留集大小
给一个进程分配的物理页框的集合就是这个进程的驻留集。
- 分配给一个进程的页框越少,驻留在主存中的进程就越多,从而可提高CPU的利用率。
- 若一个进程在主存中的页面过少,则尽管有局部性原理,缺页率仍相对较高。
- 若分配的页框过多,则由于局部性原理,对该进程的缺页率没有太明显的影响。
-
内存分配策略
在请求分页系统中,可采取两种内存分配策略,即固定和可变分配策略。在进行置换时,也可采取两种策略,即全局置换和局部置换。
- 固定分配:操作系统为每个进程分配一组固定数目的物理块,在进程运行期间不再改变。即,驻留集大小不变
- 可变分配:先为每个进程分配一定数目的物理块,在进程运行期间,可根据情况做适当的增加或减少。即驻留集大小可变
- 局部置换:发生缺页时只能选进程自己的物理块进行置换。
- 全局置换:可以将操作系统保留的空闲物理块分配给缺页进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页进程。
固定分配VS可变分配:区别在于进程运行期间驻留集大小是否可变
局部置换VS全局置换:区别在于发生缺页时是否只能从进程自己的页面中选择一个换出
三种组合方案:
-
固定分配局部置换
它为每个进程分配一定数目的物理块,在整个运行期间都不改变。
若进程在运行中发生缺页,则只能从该进程在内存中的页面中选出一页换出,然后再调入需要的页面。
-
可变分配全局置换
为系统中的每个进程分配一定数目的物理块,操作系统自身也保持一个空闲物理块队列。
当某进程发生缺页时,系统从空闲物理块队列中取出物理块分配给该进程,井将欲调入的页装入其中。
-
可变分配局部置换
它为每个进程分配一定数目的物理块,当某进程发生缺页时,只允许从该进程在内存的页面中选出一页换出动态变换,频繁缺页,分配物理块,缺页率低,减少物理块
-
物理块调入算法
采用固定分配策略时,将系统中的空闲物理块分配给各个进程,可采用下述几种算法。
- 平均分配算法,将系统中所有可供分配的物理块平均分配给各个进程。
- 按比例分配算法,根据进程的大小按比例分配物理块。
- 优先权分配算法,为重要和紧迫的进程分配较多的物理块。通常采取的方法是把所有可分配的物理块分成两部分:一部分按比例分配给各个进程;一部分则根据优先权分配。
-
调入页面的时机
为确定系统将进程运行时所缺的页面调入内存的时机,可采取以下两种调页策略:
- **预调页策略:**将预计在不久后便会被访问的页面预先调入内存;主要用于进程的首次调入,由程序员指出应先调入哪些页。
- **请求调页策略:**进程在运行中需要访问的页面不再内存而提出请求,由系统将所需页面调入内存。每次仅调入一页,增加了磁盘I/O开销。
-
从何处调入页面
请求分页系统中的外存分为两部分:用于存放文件的文件区和用于存放对换页面的对换区。
对换区采用连续分配方式,而文件区采用离散分配方式,因此对换区的磁盘IO速度比文件区的更快。这样,当发生缺页请求时,系统从何处将缺页调入内存就分为三种情况:
-
系统拥有足够的对换区空间
可以全部从对换区调入所需页面,以提高调页速度。为此,在进程运行前,需将与该进程有关的文件从文件区复制到对换区。
-
系统缺少足够的对换区空间
凡是不会被修改的文件都直接从文件区调入;而当换出这些页面时,由于它们未被修改而不必再将它们换出。但对于那些可能被修改的部分,在将它们换出时须调到对换区,以后需要时再从对换区调入(因为读比写的速度快)。
-
UNIX方式
运行之前进程有关的数据全部放在文件区,故未使用过的页面,都可从文件区调入。若被使用过的页面需要换出,则写回对换区,下次需要时从对换区调入。进程请求的共享页面若被其他进程调入内存,则无须再从对换区调入。
-
-
如何调入页面
-
当进程所访问的页面不在内存中时(存在位为0),便向CPU发出缺页中断,中断响应后便转入缺页中断处理程序。
-
该程序通过查找页表得到该页的物理块,此时如果内存未满,则启动磁盘I/O,将所缺页调入内存,并修改页表。
-
如果内存已满,则先按某种置换算法从内存中选出一页准备换出;
- 如果该页未被修改过(修改位为0),则无须将该页写回磁盘;
- 如果该页已被修改(修改位为1),则必须将该页写回磁盘,
然后将所缺页调入内存,并修改页表中的相应表项,置其存在位为1。
-
调入完成后,进程就可利用修改后的页表形成所要访问数据的内存地址。
-
3.2.4 页面置换算法
进程运行时,若其访问的页面不在内存中而需将其调入,但内存已无空闲空间时,就需要从内存中调出一页程序或数据,送入磁盘的对换区,选择调出页面的算法就称为页面置换算法。
-
最佳置换算法(OPT)
选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。
但由于人们目前无法预知进程在内存下的页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。
-
先进先出置换算法(FIFO)
优先淘汰最早进入内存的页面,即在内存中驻留时间最久的页面。
该算法实现简单,只需把调入内存的页面根据先后次序链接成队列,设置一个指针总指向最早的页面。
-
Belady异常一一当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。
只有FIFO算法回产生Belady异常,算法性能差。
该算法与进程实际运行时的规律不适应,因为在进程中,有的页面经常被访问。
-
-
最近最久未使用置换算法(LRU)
选择最近最长时间未访问过的页面予以淘汰,它认为过去一段时间内未访问过的页面,在最近的将来可能也不会被访问。
该算法为每个页面设置一个访问字段,来记录页面自上次被访问以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。
该算法的实现需要专门的硬件支持,虽然算法性能好,但是实现困难,开销大。
-
时钟置换算法(CLOCK)/最近未用算法(NRU)
简单的CLOCK算法实现方法:
- 为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。
- 当某页被访问时,其访问位置为1。
- 当需要淘汰一个页面时,只需检查页的访问位。如果是0,就选择该页换出;如果是1,则将它置为0,暂不换出,继续检查下一个页面,
- 若第一轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)
-
改进型的时钟置换算法
-
简单时钟问题:简单的时钟置换算法仅考虑到一个页面最近是否被访问过。事实上,如果被淘汰的页面没有被修改过,就不需要执行I/O操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。
因此,除了考虑一个页面最近有没有被访问过之外,操作系统还应考虑页面有没有被修改过。在其他条件都相同时,应优先淘汰没有修改过的页面,避免I/O操作。这就是改进型的时钟置换算法的思想。
修改位=0,表示页面没有被修改过:修改位=1,表示页面被修改过。
-
算法规则:将所有可能被置换的页面排成一个循环队列,用(访问位A,修改位M)表示各页面状态。
替换帧优先级:
- 1类A=0,M=0:最近未被访问且未被修改,是最佳淘汰页。
- 2类A=0,M=1:最近未被访问,但已被修改,不是很好的淘汰页。
- 3类A=1,M=0:最近已被访问,但未被修改,可能再被访问。
- 4类A=1,M=1:最近已被访问且已被修改,可能再被访问。
-
第一轮:第一优先级——最近设访问,且没修改的页面
从当前位置开始扫描到第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位
-
第二轮:第二优先级——最近没访问,但修改过的页面
若第一轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。本轮将所有扫描过的帧访问位设为0
-
第三轮:第三优先级——最近访问过,但没修改的页面
若第二轮扫描失败,则重新扫描,查找第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位
-
第四轮:第四优先级——最近访问过,且修改过的页面
若第三轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。
由于第二轮己将所有帧的访问位设为0,因此经过第三轮、第四轮扫描定会有一个帧被选中,因此改进型CLOCK置换算法选择一个淘汰页面最多会进行四轮扫描。
-
性能:算法开销较小,性能也不错
-
3.2.5 抖动和工作集
-
抖动
- 定义:抖动,又称颠簸,指在页面置换过程中,刚刚换出的页面马上又要换入主存,刚刚换入的页面马上又要换出主存。
- 抖动发生的原因:系统中同时运行的进程太多,由此分配给每个进程的物理块太少,不能满足进程正常运行的基本要求,致使每个进程在运行时频繁地出现缺页,必须请求系统将所缺页面调入内存。
- 抖动的危害:
- 使得在系统中排队等待页面调入/调出的进程数目增加。
- 对磁盘的有效访问时间也随之急剧增加,造成每个进程的大部分时间都用于页面的换入/换出,而几乎不能再去做任何有效的工作,
- 进而导致发生处理机的利用率急剧下降并趋于零的情况。
-
工作集
由于抖动的发生与系统为进程分配物理块的多少有关,于是又提出了关于进程工作集的概念。
工作集是指在某段时间间隔内,进程要访问的页面集合。
基于局部性原理,可以用最近访问过的页面来确定工作集。一般来说,工作集 W W W可由时间 t t t和工作集窗口大小 Δ Δ Δ来确定。例如,某进程对页面的访问次序如下:
假设系统为该进程设定的工作集窗口大小 Δ Δ Δ为5,则在 t 1 t_1 t1时刻,进程的工作集为{2,3,5},在 t 2 t_2 t2时刻,进程的工作集为{1,2,3,4}。
工作集大小一般会比窗口小很多,工作集反映了进程在接下来的一段时间内很有可能会频繁访问的页面集合,因此,若分配给进程的物理块小于工作集大小,则该进程就很有可能频繁缺页。
一般来说分配给进程的物理块数(即驻留集大小)要大于工作集大小。
3.2.6 内存映射文件
内存映射文件(Memory-MappedFiles)与虚拟内存有些相似,将磁盘文件的全部或部分内容与进程虚拟地址空间的某个区域建立映射关系,便可以直接访问被映射的文件,而不必执行文件 I/O 操作,也无须对文件内容进行缓存处理。这种特性非常适合用来管理大尺寸文件。
-
特性
- 进程可使用系统调用,请求操作系统将文件映射到进程的虚拟地址空间
- 以访问内存的方式读写文件
- 进程关闭文件时,操作系统负责将文件数据写回磁盘,并解除内存映射
- 多个进程可以映射同一个文件,方便共享
-
优点
- 程序员编程更简单,已建立映射的文件,只需按访问内存的方式读写即可
- 文件数据的读入/写出完全由操作系统负责,I\O效率可以由操作系统负责优化
3.2.7 虚拟存储器性能影响因素
-
页面大小
根据局部性原理,页面较大则缺页率较低,页面较小则缺页率较高。
- 页面较小时,一方面减少了内存碎片,有利于提高内存利用率;另一方面,也会使每个进程要求较多的页面,导致页表过长,占用大量内存。
- 页面较大时,虽然可以减少页表长度,但会使页内碎片增大。
-
分配给进程的物理块
分配给进程的物理块数越多,缺页率就越低,但是当物理块超过某个数目时,再为进程增加一个物理块对缺页率的改善是不明显的。
-
页面置换算法
好的页面置换算法可使进程在运行过程中具有较低的缺页率。
选择LRU、CLOCK等置换算法,将未来有可能访问的页面尽量保留在内存中,从而提高页面的访问速度。
-
写回磁盘的频率
换出已修改过的页面时,应当写回磁盘,如果每当一个页面被换出时就将它写回磁盘,那么每换出一个页面就需要启动一次磁盘,效率极低。
建立一个已修改换出页面的链表,对每个要被换出的页面(已修改),可以暂不将它们写回磁盘,而将它们挂在该链表上,仅当被换出页面数达到给定值时,才将其写回磁盘。
-
局部化程度
编写程序的局部化程度越高,执行时的缺页率就越低。如果存储采用的是按行存储,访问时就要尽量采用相同的访问方式,避免按列访问造成缺页率过高的现象。
3.2.8 地址翻译
设某系统满足以下条件:
- 有一个TLB与一个data Cache
- 存储器以字节为编址单位
- 虚拟地址14位
- 物理地址12位
- 页面大小为64B
- TLB为四路组相联,共有16个条目
- data Cache是物理寻址、直接映射的,行大小为4B,共有16组
写出访问地址为0x03d4, 0x00f1和0x0229的过程。
-
写出其地址结构
-
根据页面大小求页内偏移量与页号长度
本系统以字节编址,页面大小为64B,则页内偏移量为 l o g 2 ( 64 B / 1 B ) = 6 位 log_2(64B/1B)=6位 log2(64B/1B)=6位,所以虚拟页号为 14 − 6 = 8 位 14-6=8位 14−6=8位,物理页号为 12 − 6 = 6 位 12-6=6位 12−6=6位。
-
根据TLB结构求虚拟页号地址结构
因为TLB为四路组相联,共有16个条目,则TLB有16/4=4组,因此虚拟页号低 l o g 2 4 = 2 位 log_24=2位 log24=2位就为组索引,高6位为TLB标记。
-
根据Cache机构求物理页号地址结构
因为Cache行大小为4B,因此物理地址中低 l o g 2 4 = 2 位 log_24=2位 log24=2位为块索引,Cache共有16组,可知接下来 l o g 2 16 = 4 位 log_216=4位 log216=4位为组索引,剩下高6位作为标记。
-
-
根据TLB、页表寻找物理页号
先把十六进制的虚拟地址0x03d4, 0x00f1和0x0229转化为二进制形式,如下表所示。
得到每个地址的组索引和TLB标记,接下来就要找出每个地址的页面在不在主存中,若在主存中,则还要找出物理地址。
- 查TLB得到物理块号
- 对于0x03d4,组索引为3,TLB标记为0x03。
- 查TLB表,第3组中有标记为03的项,且有效位为1,找到物理块0D。
- 拼接页内地址(010100),得到物理地址为0x354。
- 查TLB未得到物理块号,查页表得到物理块号
- 对于0x00f1,组索引为3,TLB标记为0x00。
- 查TLB表,第3组未找到有标记为00的项。
- 访存查页表,根据虚拟页号0x03,找到物理块号02,且有有效位为1。
- 拼接页内地址(110001),得到物理地址为0x0b1。
- 查TLB未得到物理块号,查页表也未得到物理块号
- 对于0x0229,组索引为0,TLB标记为0x02。
- 查TLB表,第0组未找到有标记为02的项。
- 访存查页表,根据虚拟页号0x08,页表08项有效位为0,页面不在主存中,产生缺页中断。
- 查TLB得到物理块号
-
根据Cache寻找内存地址
找出在主存中的页面的物理地址后,就要通过物理地址访问数据,接下来要找该物理地址的 内容在不在Cache中,物理地址结构如下表所示。
- Cache块命中
- 对于0x354,Cache索引为5,Cache标记为0x0d。
- 查询Cache索引为5的行,标记为0d,有效位为1,则该块在Cache中。
- 偏移为0,即块0,可得虚拟地址0x03d4的内容为36H。
- Cache块未命中
- 对于0x0b1,Cache索引为C,Cache标记为0x02。
- 查询Cache索引为C的行,标记为02,有效位为0,则该块不在Cache中。
- 需去访问主存查找,物理页号为2、偏移为0x31的内容。
- Cache块命中
-
虚拟地址寻址总流程
3.2.9 本节小结
1)为什么要引入虚拟内存?
上一节提到过,多道程序并发执行不仅使进程之间共享了处理器,而且同时共享了主存。然而,随着对处理器需求的增长,进程的执行速度会以某种合理平滑的方式慢下来。但是,若同时运行的进程太多,则需要很多的内存,当一个程序没有内存空间可用时,那么它甚至无法运行。所以,在物理上扩展内存相对有限的条件下,应尝试以一些其他可行的方式在逻辑上扩充内存。
2)虚拟内存(虚存)空间的大小由什么因素决定?
虚存的容量要满足以下两个条件
1.虚存的实际容量 ≤ 内存容量和外存容量之和,这是硬件的硬性条件规定的,若虚存的实际容量超过了这个容量,则没有相应的空间来供虚存使用。
2.虚存的最大容量 ≤ 计算机的地址位数能容纳的最大容量。假设地址是32位的,按字节编址,一个地址代表1B存储空间,则虚存的最大容量≤4GB(2^32B)。这是因为若虚存的最大容量超过4GB,则32位的地址将无法访问全部虚存,也就是说4GB以后的空间被浪费了,相当于没有一样,没有任何意义 。
实际虚存的容量是取条件1和2的交集,即两个条件都要满足,仅满足一个条件是不行的。
3)虚拟内存是怎么解决问题的?会带来什么问题?
虚拟内存使用外存上的空间来扩充内存空间,通过一定的换入/换出,使得整个系统在逻辑上能够使用一个远远超出其物理内存大小的内存容量。因为虚拟内存技术调换页面时需要访问外存,会导致平均访存时间增加,若使用了不合适的替换算法,则会大大降低系统性能。
本节学习了4种页面置换算法,要将它们与处理机调度算法区分开。当然,这些调度算法之间也是有联系的,它们都有一个共同点,即通过一定的准则决定资源的分配对象。在处理机调度算法中这些准则比较多,有优先级、响应比、时间片等,而在页面调度算法中就比较简单,即是否被用到过或近段时间内是否经常使用。在操作系统中,几乎每类资源都会有相关的调度算法读者通过将这些调度算法作为线索,可将整个操作系统的课程连成一个整体。
3.3 本章疑难点