请页式管理

请求分页式管理

根据调入方式的不同,虚拟分页式存储管理又分为请求分页式管理与预调入页式管理。预调入页式管理,根据某种算法动态预测进程最可能访问哪些页面,在使用前预先调入内存,尽量做到进程在访问页面之前已经预先调入该页,而且每次可以调入多个页面,以减小磁盘的 IO 次数。

用得较多的分页式虚拟存储管理是请页式(Demand Paging),当需要执行某条指令或使用某个数据,而发现它们并不在主存时,产生一个缺页中断,系统从辅存中把该指令或数据所在的页面调入内存。请求分页式存储管理是在页式存储管理的基础上,增加了请求分页功能和页面置换功能实现的虚拟存储系统。当需要执行某条指令而发现它不在内存时或当某条指令需要访问其他的数据或指令时,这些指令和数据不在内存,从而发生缺页中断,于是系统将外存中相应的页面调入内存。如果此时内存能容纳新页,则启动磁盘 IO 将其调入内存,如果内存已满,则通过页面置换功能将当前所需的页面调入。

请求调页也可看做一种动态内存分配技术,它把页面的分配推迟到不能再推迟为止,在内存总数保持不变的情况下,请求调页从总体上能使系统有更大的吞吐量。但是系统为此也要付出额外的开销,这是因为由请求调页所引发的每个“缺页”异常必须由内核处理,这将浪费 CPU 的周期。在大部分应用程序中,程序的局部性原理保证了一旦进程开始在一组页上运行,在接下来相当长的一段时间内它就会一直停留在这些页上而不去访问其他的页;这样就可以认为“缺页”异常是一种稀有事件。

请页机制

当一个进程运行时,CPU 访问的地址是用户空间的虚地址。Linux 采用请页机制来节约物理内存,也就是说,它仅仅把当前要使用的用户空间中的少量页装入物理内存。当访问的虚存页面尚未装入物理内存时,处理器将向 Linux 报告一个页故障及其对应的故障原因。页故障的产生有以下三种原因:

  • 程序出现错误,例如,要访问的虚地址在 PAGE_OFFSET(3GB) 之外,则该地址无效,Linux 将向进程发送一个信号并终止进程的运行;
  • 虚地址有效,但其所对应的页当前不在物理内存中,即缺页异常,这时,操作系统必须从磁盘或交换文件(此页被换出)中将其装人物理内存。
  • 要访问的虚地址被写保护,即保护错误,这时,操作系统必须判断:如果是某个用户进程正在写当前进程的地址空间,则发送一个信号并终止进程的运行;如果错误发生在旧的共享页上时,则处理方法有所不同,也就是要对这一共享页进行复制,这就是曾经描述过的“写时复制”技术。

缺页中断

image

缺页中断与一般中断的区别:

  • 一般中断是在指令结束后接受中断请求并响应;缺页中断是在指令执行期间所要访问的指令或数据不在内存时产生和处理的
  • 一条指令在执行期间可能产生多次缺页中断

请求调页

当页从未被访问时则调用 do_no_page() 函数。有两种方法可以装入所缺的页,采用哪种方法取决于这个页是否与磁盘文件建立了映射关系。该函数通过检查虚存区描述符的 nopage 域来确定这一点,如果页与文件建立了映射关系,则 nopage 域就指向一个函数,该函数把所缺的页从磁盘装入到内存。因此,可能有以下两种情况。

  • nopage 域不为 NULL。在这种情况下,说明某个虚存区映射了一个磁盘文件,nopage 域指向从磁盘进行读入的函数。
  • nopage 域为 NULL。在这种情况下,虚存区没有映射磁盘文件,也就是说,它是个匿名映射。因此,dono_page()调用 do_anonymous_page() 函数获得一个新的页面。

对于do_anonymous_page() 函数,当处理写访问时,该函数调用 _get_free_page 分配一个新的页面,并把新页面填为 0。最后,把页表相应的表项置为新页面的物理地址,并把这个页面标记为可写和脏两个标志。

相反,当处理读访问时(所访问的虚存区可能是未初始化的数据段 BSS),因为进程正在对它进行第一次访问,因此页的内容是无关紧要的。给进程一个填充为 0 的页面要比给它个由其他进程填充了信息的旧页面更为安全。没有必要立即给进程分配一个填充为 0 的新页面,我们可以给它一个现有的称为“零页”的页,这样可以进一步推迟页面的分配。“零页”在内核初始化期间被静态分配,并存放在 empty_zero_page 变量中(一个有 1024 个长整数的数组,并用 0 填充),因此页表项被设为零 页的物理地址。由于“零页”被标记为不可写,如果进程试图写这个页,则写时复制机制被激活。当且仅 当在这个时候,进程才获得一个属于自已的页面并对它进行写。

地址变换

image