《内存管理》一节,给大家介绍了操作系统的两种内存分配方式,分别为连续分配方式和离散分配方式:
- 连续分配:给程序分配一整块连续、完整的内存空间;
- 离散分配:将程序分成若干页或者若干段,然后分散存储到内存的各个区域。
这两种内存分配方式有一个共同的缺陷,即要求将程序全部载入内存。这也就意味着,程序使用的逻辑地址空间不能超过实际的物理内存空间,否则程序将无法全部进入内存,也就无法运行。但实际场景中,很多软件的运行都需要占用大量的内存空间,比如一些大型的游戏软件。
借助虚拟存储器,操作系统可以轻松解决“小内存”和“大作业”之间的矛盾,使大作业也可以在“小内存”的计算机上正常运行。
什么是虚拟存储器?
虚拟存储器是一种以局部性原理为依据实现的内存管理机制。
所谓局部性原理,是指在程序执行过程中,CPU 无论读指令还是数据,常常出现以下两种情况:
- CPU 执行完某条指令后,过段时间还会执行该指令;CPU 访问了某个存储单元后,过段时间还会访问此存储空间;
- CPU 访问了某个存储空间后,接下来的一段时间内,它访问的往往是该存储单元附近的内存空间。
因此,一个程序的正常执行,没必要事先将所有代码和数据全部装入内存,内存中只存储 CPU 短时间内执行的指令和所需数据即可。
这也就意味着,整个程序可以采用离散存储的方式,一部分指令存储在内存中,供 CPU 短时间内执行;另一部分则存储在外存中,供 CPU 将来执行。对于存放在外存中的程序段,操作系统需要负责以下 2 项工作:
- 当 CPU 要执行的指令不在内存中时,操作系统需要将所需指令和数据调入内存;
- 如果内存空间不足,操作系统需要根据既定策略,将内存中暂时不需要执行的指令和数据移到外存,同时将需要的指令和数据移入内存。
这样的内存管理机制,保证程序可以正常执行的同时,有效解决了“小内存”和“大作业”之间的矛盾,常称为虚拟存储管理或者虚拟存储器。虚拟存储器中,将程序执行所占用的内存和一部分外存空间称为虚拟内存。
虚拟存储器具备以下 4 个特征:
- 离散型:内存分配方式采用的是离散分区分配的方式,而不是连续分配的方式。
- 多次性:一个程序的所有指令和数据,需要分批调入内存。
- 交换性:当内存空间不足时,需要将内存中暂时不用的数据移到外存,同时将需要的数据移入内存。
- 虚拟性:虚拟存储器对内存空间实现了逻辑上的扩充,即用户所能使用的内存容量远大于实际的物理内存容量(因为程序的一部分代码存储在外存中)。
虚拟存储器的实现
前面讲过,离散分配的实现方式有 3 种,分别为页式存储、段式存储和段页式存储。相应地,虚拟存储器的实现方式也有 3 种,分别称为页式虚拟存储器、段式虚拟存储器以及段页式虚拟存储器。
页式虚拟存储器是最常见的一种虚拟存储器,简单地理解,页式虚拟存储器就是在页式存储方式的基础上,通过增加请求页面调入功能和页面置换功能实现的一种虚拟存储器。
页式虚拟存储器中,整个程序分页存储在外存中。程序执行开始前,操作系统会将程序的第一个页面加载进内存。执行过程中,操作系统会不断地将 CPU 需要的程序页面加载到内存中,以保证程序的正常执行(请求页面调入功能)。当内存空间不足时,操作系统会根据既定的策略(算法),将暂时不需要的页面移出内存,然后将需要的页面移入内存(页面置换功能)。
页面置换算法
当 CPU 要执行的指令不在内存中时,操作系统负责将所需页面从外存调入内存,整个过程可能发生的意外是:内存的空闲空间太小,无法满足新调入页面的需求。这种情况下,操作系统就需要采用适当的页面置换算法,在内存中找到一些暂时不需要的页面,并将这些页面从内存移至外存,从而为新调入页面腾出足够的内存空间。
不同的页式虚拟存储器,采用的页面置换算法也不相同,常见的置换算法如下表所示。
置换算法 | 描 述 |
---|---|
先进先出置换算法(FIFO算法) | 选择那些最先进入内存的页面作为被置换页面。该算法是一种性能最差的算法。 |
最佳置换算法 | 一种理想化的算法,性能最好,但实际很难实现。该算法选择那些永远不使用的,或者最长时间内不会被使用的页面作为被置换页面。但要确定哪个页面在最长时间内不会被访问,是很难实现的。 |
最近最久未使用页面置换算法(LRU 算法) | 假设一个页面被访问过,但最近一段时间内没有再被访问过,则根据局部性原理,此页面再次被访问的概率较低。LRU 算法会选择间隔时间最长的页面作为被置换页面。
运行 LRU 算法需要很大的系统开销。 |
最近未用页面置换算法(NUR 算法) | 将最近一段时间未使用过的页面作为被置换页面。 |