操作系统(4):分页机制

1.分页机制的引入

操作系统(2):保护模式和GDT一文中,讲述了操作系统的分段机制,但是分段机制的主要作用是使计算机在保护模式下具有强大的寻址能力,并且对于保护模式下用户能够访问的物理地址进行了限制。但是如果对能够寻址的内存进行很好地分配呢?为了解决这个问题,我们需要分页机制

2.虚拟内存

每个程序拥有自己的地址空间,这个空间被分割成多个块,每一块称作一页或页面(page).每一页有连续的地址范围。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件立刻执行必要的映射。当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的指令。

虚拟地址空间按照固定大小固定大小划分成称为页面(page)的若干单元。在物理内存中对应的单元称为页框(page frame).页面和页框的大小通常是一样的,在x86下一般一个页面的大小是4kB.因此,进程与物理内存的关系示意图如下所示:

Paging

3.多级页表映射

如果按照上图所示的给进程分配内存的方法,如果有4G内存,那么由于无法细分,就需要对所有的内存分配页表,那么将需要2^20(总共地址线是32位,每页大小4kb,则页偏移量需要低12位,剩下的高20位作为页表地址)个表项来保存每个进程的页表,若每项4B,则需要4MB来存储页表。即使此时只有1个进程,并且只占用很小的内存,也要付出4MB的内存,无法实现按需映射。

而如果采用二级页表的话,则可以只为进程实际使用的那些虚拟内存区请求页表来减少页表,对于进程未使用的页暂时可以不用为其建立页表,显然这样的机制更好。

以32位的地址为例,分为3段来寻址,分别是地址的低12位,中间10位和高10位。其中高10位表示当前地址项在页目录中的偏移,最终偏移处指向对应的页表,中间10位是当前地址在该页表中的偏移,我们按照这个偏移就能查出来最终指向的物理页了,最低的12位表示当前地址在该物理中的偏移。分级页表的示意图如下:

PageMapping

显然,只进行分段时的寻址过程如下:

逻辑地址-->段机制处理-->线性地址=物理地址

而进行分页后的寻址过程为:

逻辑地址-->段机制处理-->线性地址-->页机制处理-->物理地址

至此,我们可以得到保护模式下完整的寻址过程示意图:

CompleteAddressing

4.页面置换算法

当发生缺页中断时,操作系统必须在内存中选择一个页面将其换出内存,以便为即将调入的页面腾出空间。如果要换出的页面在内存驻留期间已经被修改过,就必须把它写回磁盘以更新该页面在磁盘上的副本;如果该页面没有被修改过(如一个包含程序正文的页面),那么它在磁盘上的副本已经是吉卜赛人,不需要回写,直接用调入的页面覆盖掉被淘汰的页面就可以了。

当发生缺页中断时,虽然可以随机地选择一个页面来置换,但是如果每次都选择不常使用的页面会提升系统的性能。如果一个被频繁使用的页面被置换出内存,很可能它在很短的时间内又要被调入内存,这会带来不必要的开销。因此,我们需要选择合适的页面置换算法来提升系统的性能。

4.1 最优页面置换算法

当中断发生时,有些页面在内存中,其中有一个页面将很快被访问,而其他页面可能要到10,100甚至1000条指令后才会被访问,显然,此时应该置换要到1000条指令后才访问的页面,因为这样就可以把因为需要调入这个页面而发生的缺页中断推迟到来。

但是这个算法的问题在于无法实现,因为我们不知道哪一个页面会在执行1000条指令后被执行。这个算法的唯一意义可能就是可用于衡量其他可实现的页面置换算法的性能,如果操作系统达到的页面置换算法性能只比最优算法差1%,那么就可以断定这个系统的页面置换性能是比较好的。

4.2 最近未使用页面置换算法

4.3 先进先出(FIFO)页面置换算法

4.4 第二次机会页面置换算法

4.5 时钟页面置换算法

4.6 最近最少使用(Least Recently Used,LRU)页面置换算法

4.7 最不经常使用(Not Frequently Used,NFU)页面置换算法

4.8 老化算法

4.9 工作集算法

4.10 工作集时钟算法