为了更高效的利用处理器和IO设备,需要在内存中运行更多的进程;同时使程序开发时不受内存大小的影响,而解决这两个问题的方法是使用虚拟内存技术。
通过虚拟内存技术,将本要分配在实内存的进程,可以部分分配到磁盘上,当需要访问时再将其换出到实内存里。使用逻辑地址访问访问,在运行时转为实地址,让使用者感觉使用的是更大的一片内存。而分配在磁盘的存储空间,被称为虚拟内存。
如果不使用虚拟内存技术,当没有使用覆盖技术时,就必须将进程的所有页存储在内存里;而使用虚拟内存时,可以将当前运行的进行页存储到内存页框里,非运行的进程页存储到磁盘里,在需要时读入到内存(当将一页读入到内存时,就可能将一页写入到内存里)。虚拟存储技术可以和分段、分页的内存管理技术相结合,具体有虚拟分页、虚拟分段等内存分配方式。(关于覆盖技术和交换技术的区别见此)
支持虚拟内存技术的两个基本方法是分页和分段。对于分页,每个进程化分为相对比较小且大小固定的页,而分段可以使用大小可变的块。还可以把分页和分段组合在一个内存管理方案中。
由于可以通过逻辑地址访问,同时在运行时转化为实地址,因此虚拟内存技术允许一个进程分布在不连续的内存块里,并且可以随时间的变化而改变,甚至可以运行时不需要将所有的块存储在内存里。
虚拟内存管理方案要求硬件和软件的支持。硬件支持由处理器提供,包括把虚拟地址动态转换为物理地址,当访问的页或端不在内存时产生一个中断。这类中断触发操作系统中的内存管理软件。
简单分页 | 虚存分页 | 简单分段 | 虚存分段 |
---|---|---|---|
内存被划分为成大小固定的小块、称作页框 | 内存被划分为大小规定的小块,称作页框 | 内存未被分配 | 内存未被分配 |
程序被编译器或内存管理系统划分成页 | 程序被编译器或内存管理器系统划分成页 | 由程序员给编译器指定程序段 | 由程序员给编译器指定程序段 |
页框内有内部碎片 | 页框内有内部碎片 | 没有内部碎片 | 没有内部碎片 |
没有外部碎片 | 没有外部碎片 | 有外部碎片 | 有外部碎片 |
操作系统必须为每个进程维护一个页表,以说明每个页对应的页框 | 操作系统必须为每个进程维护一个页表,以说明每个页对应的页框 | 操作系统必须为每个进程维护一个段表、以说明每一段中的加载地址和长度 | 操作系统必须为每个进程维护一个段表、以说明每一段中的加载地址和长度 |
操作系统必须维护一个空闲页框列表 | 操作系统必须维护一个空闲页框列表 | 操作系统必须维护一个内存中空闲的空洞列表 | 操作系统必须维护一个内存中空闲的空洞列表 |
处理器使用页号和偏移量来计算绝对地址 | 处理器使用页号和偏移量来计算绝对地址 | 处理器使用段号和偏移量来计算绝对地址 | 处理器使用段号和偏移量来计算绝对地址 |
当进程运行时,所有页必须都在内存中,除非了覆盖技术 | 当进程在运行时,并不是所有页都要在页框中,只有需要时才读入页 | 当进程在运行时,所有段都必须在内存中,除非使用覆盖技术 | 当程序运行时,并不要求所有的段都必须在内存中,只在需要时才读入段 |
把一页读入内存可能需要把另一页写到磁盘 | 把一段读入内存可能需要把另一段或几个段写出到磁盘 |
进程页可以在请求时读取;或者使用预先分页策略,使用的簇的方式一次读取许多页
决定一个进程块驻留在实存的什么地方。当在纯粹的分段系统中,放置策略并不是重要的设计问题,因为有最佳适配、首次适配等都可以选择。但对于在纯粹的分页系统或段页式的系统,如何放置通常没有关系的,因为地址转换硬件和内存访问硬件可以以相同的效率为任何页框组合执行它们的功能。
有一个关注放置问题的领域是非一致性存储访问(NonUiform Memory Access,NUMA)多处理器。在非一致性存储访问多处理器之中,机器分布的共享内存可以被该机器的任何处理器访问,但访问某一特定的物理单元所需要的时间随处理器和内存模块之间距离的不同而改变。因此其性能很大程度上依赖于数据驻留的位置与使用此数据的处理器的距离。对于NUMA系统,自动放置策略希望能把也分配到能够提供最佳性能的内存。
用于处理在必须读取一个页时,要置换内存中的哪个页的情况,其目标是移除最近不可能访问的页。由于局部性原理,最近访问历史和最近将要访问的模式间有很大的相关性,因此大多数策略都基于过去的行为来预测将来的行为。
置换策略有许多使用的算法,要注意的是关于置换策略的一个约束:内存中的某些页框可能是被锁定的,即当前保存在该页框的页就不能被置换。大部分操作系统内核和重要的控制结构就保存在锁定的页框中,同时I/O缓冲区和其他对时间要求严格的区域页框内锁定在内存的页框中。锁定是通过给每个页框关联一个LOCK位实现的,这一位可以包含在页框表和当前页表里。
基本算法:
对于分页式的虚拟内存,在准备执行时,不需要也不可能把一个进程的所有页都读取到内存。因此操作系统必须决定要读取多少页,即给特定的进程分配多大的内存空间。这要考虑以下因素:
基于这些因素,操作系统常常使用两种策略:
两种策略的关联: 使用固定分配策略,则意味着使用局部置换策略:为保持驻留集大小固定,从内存中移出的一页必须由同一个进程的另一个页置换。因此有以下三种组合:
分配策略 | 局部置换 | 全局置换 |
---|---|---|
固定分配 | 一个进程的页框数是固定的;从分配给该进程的页框中选择被置换的页 | 不可能 |
可变分配 | 分配给一个进程的页框数可以不断地变化,用于保存该进程的工作集合;从分配给该进程的页框中选择被置换的页 | 进程驻留集的大小不断变化;从内存中的所有可用页框中选择被置换的页 |
与读取策略相反,此策略用于何时将一个被修改过得页写回到辅存。有两种选择:请求式清除和预约式清除。
一个比较好的方法是结合页缓冲技术,只清除可以用于置换的页,但去除了清除和置换操作之间的成对关系。被置换的页可以放置在两个表里:修改和未修改。修改表的页可以周期性地被成批写出,并移到未修改表里。未修改表的一页或因为被访问而被回收,或它的页框被分配该另一页时被淘汰。
影响驻留在内存中的进程数目,称作为系统并发度。如果某一时刻进程驻留少,则所有进程同时处于阻塞状态概率较大,因而有许多时间花费在交互上;如果驻留过多,平均驻留集合大小不够用,就会频繁发生缺页中断,从而导致抖动。
随着系统并发度的增加,刚开始很少出现所以驻留进程都被阻塞的情况,处理器利用率随着增加;当达到某一点,平均驻留集不够使用,缺页率中断数目迅速增加,出现抖动,从而使处理器利用率下降。
解决这个问题有多种方法:
如果让系统并发度减少,则要让一个或多个进程被挂起(换出),其被挂起(换出)的可能性有以下几种: