前言
本文介绍操作系统里的虚拟内存技术,它是目前最常用的内存扩充技术。
本文先介绍了虚拟内存的概念,
再介绍如何实现虚拟内存,只以请求分页管理方式为例来表示如何实现;
再比较各种页面置换算法,用以确定将哪个页面换出到外存;
最后是操作系统如何给进程页面分配、置换的策略;
从以上几个方面来理解虚拟内存技术。
虚拟内存技术的概念
传统存储管理方式的特征、缺点
- 特征1,一次性:作业必须一次性全部装入内存后才能开始运行。
这会造成以下两个问题:
- 作业很大时,不能全部装入内存,导致大作业无法运行;
- 当大量作业要求运行时,由于内存无法容纳所有作业,因此只有少量作业能运行,导致多道程序并发度下降。
- 特征2,驻留性:一旦作业被装入内存,就会一直驻留在内存中,直至作业运行结束;
由于局部性原理,将会导致了内存中会驻留大量的、暂时用不到的数据,浪费了宝贵的内存资源。
这些问题都将通过虚拟内存技术解决。
局部性原理
局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。
- 时间局部性
如果执行了程序中的某条指令,那么不久之后这条指令很有可能再次执行;
如果某个数据被访问过,不久之后该数据很可能再次被访问(因为程序中存在大量的循环); - 空间局部性
如果程序访问了某个存储单元,那么不久之后其附近的内存单元也很有可能被访问(因为很多程序在内存中都是连续存放的)。 - 高速缓存技术就是局部性原理的应用;
将近期会频繁访问到的数据放到更高速的存储器中,暂时用不到的数据放在更低速存储器中。
快表机制就是高速缓冲技术思想的典型应用;
虚拟内存的定义和特征
基于局部性原理,就可以在程序装入时,可以将程序中很快会用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行;
在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外面调入内存,然后继续执行程序;
若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存;
在操作系统的管理下,在用户看来似乎有一个比实际内存大的多的内存,这就是虚拟内存。
- 虚拟内存的容量:
- 虚拟内存的最大容量:
由CPU寻址范围确定的,32位即4G可用内存; - 虚拟内存的实际容量:
由 min(CPU寻址范围,内存和外存容量之和)决定;
- 虚拟内存的特征:
- 多次性:
无需在作业运行时一次性全部装入内存,而是运行被分成多次调入内存; - 对换性:
在作业运行时无需一直常驻内存,而是允许在作业运行过程中,将作业换入、换出; - 虚拟性:
从逻辑上扩充了内存的容量,使用户看到的内存容量,远远大于实际的容量。
如何实现虚拟内存技术
与传统的非连续分配存储管理方式上的主要区别是添加请求调页功能和页面置换功能;
- 请求调页功能:
在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外面调入内存,将缺失页面从外存调入内存,然后继续执行程序; - 页面置换功能:
若内存空间不够,由操作系统负责将内存中暂时用不到的页面换出到外存;
请求分页存储管理
操作系统 内存管理 分页/分段/段页式管理
页表机制
请求分页管理中,为了实现请求调页,操作系统需要知道每个页面是否已经调入内存;如果没有调入,也么也需要知道该页面在外存中存放的位置;
当内存空间不够时,要实现页面置换,操作系统也需要通过某些指标来决定到底换出哪个页面;有的页面没有被修改过,就不用再浪费时间写回外存;有的页面修改过,就需要将外存中的旧数据覆盖,因此操作系统也需要记录各个页面是否被修改的信息。
缺页中断机构
- 在请求分页系统中,每当要访问的页面不在内存时,便产生一个缺页中断,然后由操作系统的缺页中断处理程序处理中断。此时缺页的进程阻塞,放入阻塞队列,调页完成后再将其唤醒,放回就绪队列。
- 如果内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中相应的页表项;
如果内存中没有空闲块,则由页面置换算法选择一个页面淘汰,若该页面在内存期间被修改过,则要将其写回外存,未修改过的页面不用写回外存。 - 缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,因此属于内中断。
- 一条指令在执行期间,可能产生多次缺页中断。
地址变换机构
- 在具有快表机构的请求分页系统中,访问一个逻辑地址时,若发生缺页,则地址变换步骤是:
查快表(未命中)
–> 查慢表(发现未被调入内存)
–> 调页(调入的页面对应的表项会直接加入快表中)
–> 查快表(命中)
–> 访问目标内存单元 - 注意:
- 只有写指令才需要修改修改位。
并且一般来说只需要修改快表中的数据,只有要将快表项删除时才需要写回内存中的慢表,这样可以减少内存访问次数。 - 和普通的中断处理一样,缺页中断处理依然需要保留CPU现场;
- 需要用某种页面置换算法,来决定一个换出页面
- 换入/换出页面都需要启动慢速IO操作,可见,如果换出/换出太频繁,会有很大的开销;
- 页面调入内存后,需要修改慢表,同时也需要将表项复制到快表中。
- 地址变换流程图
页面置换算法
在请求分页存储管理中,当内存空间不够时,需要使用页面置换算法来决定将哪个页换出到外存。因为页面的换入/换出是IO操作,会有较大的开销,因此好的页面置换算法应该追求更少的缺页率。
最佳置换算法OPT
- 算法思想:
每次选择淘汰的页面将是以后永不使用、或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。 - 优缺点:
最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面,操作系统无法提前预判页面访问序列,因此最佳置换算法是无法实现的。
先进先出置换算法 FIFO
- 算法思想:
每次选择淘汰的页面是最早进入内存的页面。 - 会产生Belady异常:
当为进程分配的物理块数增大时,缺页次数不减反增的异常现象; - 优缺点:
FIFO算法实现虽然简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问,因此算法性能差。
最近最久未使用置换算法 LRU
- 算法思想:
每次淘汰的页面是最近最久未使用的页面; - 优缺点:
该算法的实现需要专门的硬件支持,算法性能好,是最接近OPT算法的,但是实现困难,开销大;
时钟置换算法 CLOCK,NRU
时钟置换算法是一种性能和开销比较均衡的算法,又称为CLOCK算法,或最近未使用算法(NRU,Not Recently Used)
- 简单的算法思想:
为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个环形队列。
当页面被访问时,其访问位为1;
当需要淘汰一个页面时,只需检查页的访问位;如果是0,就将该页换出;如果是1,则将他置为0,暂不换出,继续向下检查直到找到为0的;
若所有页面都是1,则会在第一轮扫描后全部被置为0;第二轮扫描时就会将首位换出。
因此简单的CLOCK算法选择一个淘汰页面最多会经历两轮扫描; - 优缺点:
实现简单,算法开销小,但未考虑到页面是否被修改过;
改进型时钟置换算法
- 改进型的时钟置换算法思想:
简单的时钟置换算法只考虑到一个页面最近是否被访问过,但事实上,如果被淘汰的页面没有被修改过,就不需要执行IO操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。
所以,应该优先淘汰没有被修改过的页面,避免IO操作;
在表项中添加修改位,为0表示没有被修改过,为1表示修改过。 - 算法规则如下所示:
- 优缺点:
算法开销较小,性能也不错。
页面分配策略
驻留集
驻留集是指请求分页存储管理中给进程分配的物理块的集合;
在采用了虚拟存储技术的操作系统中,驻留集大小一般小于进程的总大小;
若驻留集太小,会导致频繁缺页,性能消耗大;若驻留集太大,会导致多道程序并发度下降,资源利用率低;所以应该选择一个合适的驻留集大小。
页面分配、置换策略
- 页面分配:
- 固定分配:
操作系统为每个进程分配一组固定数目的物理块,在进程运行期间不再改变,即驻留集大小不变; - 可变分配:
先为每个进程分配一定数据的物理块,在进程运行期间,可根据情况做适当的增加或减少,即驻留集可变;
- 置换策略:
- 局部置换:
发生缺页时只能选择进程自己的物理块进行置换 - 全局置换:
可以将操作系统保留的空闲物理块分配给缺页进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页进程;
- 可变分配全局置换和可变分配局部置换区别
可变分配全局置换:只要缺页就给分配新物理块
可变分配局部置换:要根据发生缺页的频率来动态的增加或减少进程的物理块
固定分配局部置换
系统为每个进程分配一定梳理的物理块,在整个运行期间都不改变;
若进程在运行中发生缺页,则只能从该进程在内存中的页面中选出一页换出,然后再调入需要的页面;
这种策略的缺点是:很难在刚开始就确定应为每个进程分配多少个物理块才算合理。
可变分配全局置换
刚开始会为每个进程分配一定数量的物理块,操作系统会保持一个空闲物理块队列;
当某进行发送缺页时,从空闲物理块中取出一块分配给该进程;若已无空闲物理块,则可选择一个未锁定的页面换出外存,再将该物理块分配给缺页的进程。
采用这种策略时,只要某进程发生缺页,都将获得新的物理块,仅当空闲物理块用完时,系统才会选择一个未锁定的页面调出,被选择调出的页可能是系统中任何一个进程的页,因此该被选中的进程物理块会减少,缺页率增加。
可变分配局部置换
刚开始为每个进程分配一定数量的物理块,当某进程发生缺页时,只允许从该进程自己的物理块中选出一个进行换出外存;
如果进程在运行中频繁缺页,系统会为该进程多分配几个物理块,直至该进程缺页率趋势到适当程度;反之,如果进程在运行中缺页率极低,则可适当的减少分配给该进程的物理块;
何时调入页面
- 预调页策略
一般用于进程运行前,由程序员指出应该先调入哪些部分; - 请求调页策略
进程运行时,发生缺页再调页。
从何处调入页面
- 对换区足够大:
在进程运行前,将数据从文件区复制到对换区,之后所有的页面调入、调出都是在内存与对换区之间进行; - 对换区不够大:
不会修改的数据每次都从文件区调入,会修改的数据调出到对换区,需要时再从对换区调入; - UNIX方式:
第一次使用时的页面全部都文件区调入;调出的页面都写回对换区,再次使用时从对换区调入;
抖动(颠簸)现象
是指刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,这种频繁的页面调度行为成为抖动,或颠簸。
产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理块数。
- 工作集:
指在某段时间内,进程实际访问页面的集合; - 操作系统为根据窗口尺寸来算出工作集;
实际应用中,操作系统可以统计出进程的工作集大小,根据工作集大小给进程分配若干内存块。 - 一般来说,驻留集大小不能小于工作集大小,否则进程运行过程中将会频繁缺页,可能导致抖动现象。