当进程运行时,先将其一部分装入内存,另一部分暂留在磁盘,当要执行的指令或访问的数据不在内存时,由操作系统自动完成将它们从磁盘调入内存的工作。
虚拟地址空间即为分配给进程的虚拟内存。
虚拟地址是在虚拟内存中指令或数据的位置,该位置可以被访问。
包括以下三个要点:
虚拟页式存储管理系统:虚拟存储技术+页式存储管理方案。
虚拟页式的基本思想在于:
进程开始运行之前,不是装入全部页面,而是装入一个或零个页面,之后根据进程运行的需要动态的装入其他页面,当内存已满,而又要重新装入新的页面时,则根据某种算法置换内存中的某个页面,以便装入新的页面。
具体有两种方式:
页表是由页表项组成的。页表项的设计是由硬件保证的,表项的组成如下表所示。
表2-1 页表项的组成
属性 | 说明 |
---|---|
页框号 | 即内存块号,也称物理页面号 |
有效位 | 也称中断位,表示该页是在内存还是在磁盘,通常值为0表示相应内容尚未读入内存 |
访问位 | 引用位,表示该页是否被访问过 |
修改位 | 此页在内存中是否被修改过 |
保护位 | 页的读/写权限 |
1 关于32位虚拟地址空间的页表规模?
页面大小为4K,页表项大小为4字节,则一个进程地址空间有【232/(4K)=232/212=220】页;其页表需要占【4K/4=1K=1024】页。
2 关于64位虚拟地址空间的页表规模?
页面大小为4K,页表项大小为8字节;页表规模达到32000TB。可想而知是多么大。因此需要实现将页表页在内存中不连续存放,基本思想是为页表页创建地址索引表,即页目录(Page Directory)。
有上述的分析可知地址转换的步骤是,从虚拟地址空间出发:虚拟地址–》查页表–》得到页框号–》形成物理地址。但每个进程一张页表,资源消耗很大,所以引入倒排页表,其基本思路是:
从物理地址空间出发,系统建立一张页表;
页表项记录进程i的信息、进程i的某虚拟地址(虚页号)与页框号的映射关系。
在二级页表或者多级页表中,上述的地址映射过程存在至少两次的内存访问,这样会导致CPU的指令处理速度与内存指令的访问速度差异大,CPU的速度得不到充分利用。为了加快地址映射速度,改善系统性能,利用程序访问的局部性原理引入了快表。
TLB——Translation Look-aside Buffers,在CPU中引入的高速缓存,可以匹配CPU的处理速率和内存访问的速度。TLB是一种存取型存储器,除连线寻址机制外,还有接线逻辑,能按特定的匹配标志在一个存储周期内对所有的字同时进行比较。TLB也称为相联存储器(associative memory),特点是按内容并行查找,保存正在运行的进程的页表的部分页表项。
如上图所示,由虚拟地址映射到物理地址主要还在于求取页框号,因为物理地址的页内偏移量和虚拟地址的页内偏移相同。MMU每次处理的时候都先从TLB中匹配,如果命中了则获得页框号,否则到页表中去查询页框号,此时要注意有效位,如果是1表示页框内容已经读入内存中了,如果有效位是0则出现Page fault异常,进而转入操作系统,由操作系统从磁盘将相应页面调入内存。
又称页面错误、页面失效,是地址映射过程中硬件产生的异常。产生原因:
是指地址映射过程中,硬件检查页表时发现所要访问的页面不在内存,则产生该异常。
操作系统执行缺页异常处理程序:获取磁盘地址,启动磁盘将该页调入内存。
表示给每个进程分配的页框的数量。包括固定分配策略和可变分配策略。
表5-1 驻留集分配策略
分配策略 | 特征 |
---|---|
固定分配策略 | 进程创建时确定 |
可变分配策略 | 根据缺页率评估进程局部性表现进而决定增加还是减少页框数,但是增减页框数会带来系统开销 |
当内存中没有空闲页框,需要将一些页框换出去,这个就叫置换。置换一个页框包含两个核心问题:置换范围和置换策略。
表5-2 置换范围
置换范围 | 特征 |
---|---|
局部置换策略 | 仅在产生本次缺页的进程的驻留集中选择 |
全局置换策略 | 将内存中所有未锁定的页框都作为置换的候选 |
这里以可变分配策略的局部置换作为例子说明流程:
1)、当一个新进程装入内存时,分配一定数目的页框,然后填满这些页框;
2)、当发生一定缺页异常时,从发生异常的进程的驻留集中选择一页用于置换;
3)、不断评估进程页框分配情况,增加或减少分配给它的页框以提高整体性能。
确定了置换范围,就要进一步确定究竟该置换哪一个页框,这就需要置换策略。无论是何置换策略,核心的目标都在于置换最近最不可能访问的页,因此大多数置换策略都是基于过去的行为来预测未来的行为。但要注意:置换策略设计得越精致复杂,实现所需要的软硬件开销就越大。
置换的约束:不能置换被锁定的页框。
由于采用的虚存技术有可能调用磁盘,需要额外的开销,这就使得程序运行时间不确定。为了使得运行时间可预测,所以为每一页框增加一个锁定位,实现不让操作系统将进程使用的页面换出内存。
例如操作系统的核心代码、关键数据结构、I/O缓冲区,特别是正在I/O的内存页面都需要设置锁定位。
1 分页守护进程
从进程的驻留集中收回页框。实际上,虚拟页式系统的最佳状态是当发生缺页异常时,系统中有大量的空闲页框。所以要在系统中保存一定数目的页框供给比使用所有内存且在需要时搜索并置换一个页框有更好的性能。
清除策略的实现机制是:
1)、设计一个分页守护进程paging daemon,多数时候睡眠着,可定期唤醒以检查内存的状态;
2)、如果空闲页框过少,分页守护进程通过预定的页面置换算法选择页面换出内存;
3)、如果页面装入内存后被修改过,则将它们写回磁盘。因此分页守护进程可保证所有的空闲页框是“干净”的。
2 页缓冲技术
当进程需要使用一个已经被置换出的页框时,如果该页框还没有被新的内容覆盖,将它从空闲页框集合中移出即可恢复该页面。这就是也缓冲机制,具体实现为:
1)、不丢弃置换出的页,将它们放入两个表之一:如果未被修改过则放到空闲页链表,否则放到修改页链表中;
2)、被修改的页定期写回磁盘(不是每次修改都写,减少I/O的次数,提升性能)
3)、被置换的页仍然保留在内存中,一旦进程又要访问该页,可以迅速将它加入该进程的驻留集合。
又称页面淘汰算法。
置换以后不再需要的或在最远的将来才会用到的页面。
但是由于进程运行过程并不知道以后用到的页面,所以该算法难以实现。该算法的最佳意义在于作为一种标准来衡量其他算法的性能。
置换在内存中驻留时间最长的页。通过页面链表法,每次置换链表头的页面。
FIFO页面置换算法会产生Belady异常现象,即:当分配给进程的物理页面数增加时,缺页次数反而增加。
全称Second Chance 。是对FIFO算法改进,按照先进先出算法从链表头选择一个页框,检查其访问位R,如果为0(表示近期未被访问),则置换该页;如果为1,则给第二次机会,将该页放置到链表末尾并将访问位置0。
SCR的思想基于链表,如果访问R为1,要将该页框从链表头取出加入表尾,这个摘链和挂链的过程有消耗,所以采用基于循环链表的时钟算法。通过移动指针选择要被置换的页框。
全称Not Recently Used,是指置换在最近一段时间内未使用过的一页。
设置页表表项的两位:访问位R、修改位M。启动一个进程时,R、M为置0,R位被定期清零(复位)。
表6-1 NRU算法的R、M的可能值
编号 | R | M | 描述 |
---|---|---|---|
1 | 0 | 0 | 无访问,无修改 |
2 | 0 | 1 | 无访问,有修改 |
3 | 1 | 0 | 有访问,无修改 |
4 | 1 | 1 | 有访问,有修改 |
如上表所示,NRU算法的思想在于:从编号最小的非空类中随机选择一页置换。如果编号为1的类中为空,则从编号为2的类中寻找。
1、从指针的当前位置开始,扫描页框缓冲区,选择遇到的第一个页框(R=0,M=0)用户置换;
2、如果第1步失败,则重新扫描,选择第一个(R=0,M=1)的页框(如果R=1则跳过),扫描过程中将其跳过的页框的访问位R置0;
3、如果第2步也失败了,指针将回到最初的位置,并且集合中所有的页框的访问位R都为0了。此时再重复第1步,如果有必要接着重复第2步,这样就能找到需要置换的页框。
全称Least Recently Used,是指置换最后一次访问时间距离当前时间最长的一页,即置换未使用时间最长的一项。
基本实现是利用时间戳或维护一个访问页的栈。该算法优点在于性能最接近OPT,缺点是开销较大。
全称Not Frequently Used,是指选择访问次数最少的页面置换。
NFU算法实际上市LRU算法的一种软件解决方案。其基本实现机制在于:
1)、维护一个软件计数器,每页有一个,初值为0;
2)、每次时钟中断时,计数器加R;
3)、发生缺页中断时,选择计数器值最小的一页置换。
老化算法实际上是对NFU算法的一种改进,也是一种LRU的模拟算法。基本思想是:计数器在加R前先右移一位,并将R位加到计数器的最左端。
如下图所示,每次时钟中断的时候,根据访问位R的值修改技术器的值:如果访问位是1,则右移一位然后最高位置1;如果访问位是0,则右移一位。当发生缺页中断的时候,则选择计数器值最小的页框置换出去。
页面置换算法
页面尺寸的大小
程序的编制方法
分配给进程的页框数量
颠簸(Thrashing,也称抖动):在虚存中,页面在内存与磁盘之间频繁调度,使得调度页面所需的时间比进程实际运行的时间还多,这样导致系统效率急剧下降,这就是颠簸现象。
需要考虑的因素:
1、内部碎片
2、页表长度
3、辅存的物理特性
大页面换进换出内存的频率低一些,但是容易产生内部碎片,小页面则刚好相反。一般情况最优页面大小公式为:2*(进程平均规模*页表项的长度)的二分之一次方。不过一般操作系统会采用常用页面尺寸,如4K、4M等。
根据局部性原理,一般情况下,进程在一段时间内总是集中访问一些页面,这些页面称为活跃页面,如果分配给一个进程的物理页面数太少了,则该进程所需的活跃页面不能全部装入内存,则进程在运行过程中将频繁发生缺页中断。如果应该为进程提供与活跃页面数相等的物理页面数,这样可以大大减少缺页中断次数。
工作集:一个进程当前正在使用的页框集合。
工作集W(t,△)=该进程在过去的△个虚拟时间单位中访问到的页面的集合。
内容取决于三个因素:
1、访页的序列特性;
2、时刻t;
3、工作集窗口长度△,越长工作集越大。
在工作集算法中,基本思路是找出一个不在工作集中的页面并置换,为此每个页表项中有一个字段记录该页面最近一次被访问的时间。实现流程如下。
扫描所有的页表项,依次执行如下操作:
1、如果一个页面的R位是1,则将该页面的最后一次被访问的时间设为当前时间,将R位清零;
2、如果R位是0,则检查该页面的被访问时间是否在“当前时间-T”之前,
1)、如果是,则该页面为被置换页面;
2)、若不是,记录当前所有被扫描过页面的最后访问时间里面的最小值,扫描下一个页面并重复第1步和第2步。
如下表所示。
表6-2 页面置换算法小结
算法 | 评价 |
---|---|
OPT | 不可实现,但可作为其他算法的衡量基准 |
NRU | LRU算法很粗略的近似 |
FIFO | 可能置换出重要的页面,引起Belady异常 |
Second Chance | 相较FIFO有很大的改善 |
Clock | 实现的 |
LRU | 很优秀,但很难实现 |
NFU | LRU的相对粗略的近似 |
Aging | 非常近似LRU的有效算法 |
Working set | 实现起来开销很大 |
在对以上重点内容学习之后,再对两个概念进行补充说明。
进程通过一个系统调用(mmap)将一个文件映射到其虚拟地址空间的一部分,访问这个文件就像访问内存中的一个大数组,而不是对文件进行读写。在多数实现中,并非一次性读入所有页面的内容而是在访问页面的时候以一次一页的方式读入。
例如进程T1、T2共享了物理内存的三个页面P1、P2、P3,由于页面被共享,所以每个页面都被标记成了写时复制(由只读标记加上另一个标记组合而成)。当T2试图改变P2页面的数据后,但是和只读标记产生了冲突,产生Page Fault异常,进入了操作系统,操作系统检查出了该页面是个写时复制的页面,于是在内存中在物理内存中另开辟了一个页面P2-Copy,把相应内容写入该页中。复制的页面P2-Copy对于执行写操作的进程是私有的,对其它所有共享写时复制页面的进程是不可见的。