预计阅读本页时间:-
3.5.5 共享页面
另一个设计问题是共享。在大型多道程序设计系统中,几个不同的用户同时运行同一个程序是很常见的。显然,由于避免了在内存中有一个页面的两份副本,共享页面效率更高。这里存在一个问题,即并不是所有的页面都适合共享。特别地,那些只读的页面(诸如程序文本)可以共享,但是数据页面则不能共享。
如果系统支持分离的I空间和D空间,那么通过让两个或者多个进程来共享程序就变得非常简单了,这些进程使用相同的I空间页表和不同的D空间页表。在一个比较典型的使用这种方式来支持共享的实现中,页表与进程表数据结构无关。每个进程在它的进程表中都有两个指针:一个指向I空间页表,一个指向D空间页表,如图3-26所示。当调度程序选择一个进程运行时,它使用这些指针来定位合适的页表,并使用它们来设立MMU。即使没有分离的I空间和D空间,进程也可以共享程序(或者有时为库),但要使用更为复杂的机制。

在两个或更多进程共享某些代码时,在共享页面上存在一个问题。假设进程A和进程B同时运行一个编辑器并共享页面。如果调度程序决定从内存中移走A,撤销其所有的页面并用一个其他程序来填充这些空的页框,则会引起B产生大量的缺页中断,才能把这些页面重新调入。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
类似地,当进程A结束时,能够发现这些页面仍然在被使用是非常必要的,这样,这些页面的磁盘空间才不会被随意释放。查找所有的页表,考察一个页面是否共享,其代价通常比较大,所以需要专门的数据结构记录共享页面,特别地,如果共享的单元是单个页面(或一批页面),而不是整个页表。
共享数据要比共享代码麻烦,但也不是不可能。特别是在UNIX中,在进行fork系统调用后,父进程和子进程要共享程序文本和数据。在分页系统中,通常是让这些进程分别拥有它们自己的页表,但都指向同一个页面集合。这样在执行fork调用时就不需要进行页面复制。然而,所有映射到两个进程的数据页面都是只读的。
只要这两个进程都仅仅是读数据,而不做更改,这种情况就可以保持下去。但只要有一个进程更新了一点数据,就会触发只读保护,并引发操作系统陷阱。然后会生成一个该页的副本,这样每个进程都有自己的专用副本。两个复制都是可以读写的,随后对任何一个副本的写操作都不会再引发陷阱。这种策略意味着那些从来不会执行写操作的页面(包括所有程序页面)是不需要复制的,只有实际修改的数据页面需要复制。这种方法称为写时复制,它通过减少复制而提高了性能。