Tanenbaum 在本段中描述了两种技术:
当一个进程启动时,它的所有页表条目都被标记为不在内存中。> 一旦引用任何页面,就会发生页面错误。操作系统然后设置 > R 位(在其内部表中),更改页表条目以指向正确的页面, > 模式为只读,并重新启动指令。
这种技术也称为按需分页(如果发生页面错误,页面会按需从磁盘加载到内存)。我至少可以想到两个你想要这样做的原因:
内存消耗:只有真正需要的页面才会从磁盘加载到主内存中,您的程序中可能有部分您从未执行过,或者您的数据部分中的某些部分您在执行期间从未写入过。在这种情况下,这些部分永远不会被加载,这意味着您有更多的 RAM 可用于其他进程。如今,拥有大量内存,您当然可以争论这是否仍然是一个有效的论点。
速度:从磁盘加载很慢,十年前要慢得多。以懒惰的方式按需进行页表设置允许延迟从磁盘获取块。一次加载所有内容可能会延迟程序的执行。同样,磁盘现在速度更快,而 SSD 使这个论点更加无效。另一方面,由于动态库,二进制文件不是那么大,通常只需要一些页面错误,直到它们被加载到 RAM 中。
如果页面随后被修改,将发生另一个页面错误,允许操作系统设置 M 位并将页面的模式更改为 READ/WRITE。
同样,这样做的原因是内存消耗。在过去,内存稀缺,交换(如果内存已满,则将页面再次移回磁盘)是一种解决方案,可以为您提供更大的工作页面集的错觉。如果一个页面之前已经被换出并且从未在两者之间进行过修改,那么您可以通过删除页表中的当前位来摆脱该页面,从而释放该页面先前占用的内存以加载另一个帧。修改后的位可以帮助您检测是否需要将页面的新版本写回磁盘,或者您是否实际上可以保留旧版本并在需要时再次将其换回。
您提到的设置进程并预先填充所有页表条目(也称为预分页)的方法是完全有效的。您正在用内存消耗换取速度。页表遍历和设置修改位是在硬件中实现的(在 x86 上),这意味着它的性能还不错。但是,预填充使您免于执行页面错误处理程序,尽管通常进行了大量优化,但它是在软件中实现的。