18 分页:介绍
有时说操作系统采用两种方法之一 来解决大多数空间管理问题。 第一种方法 是将事物分割成可变大小的部分,就像我们在虚拟内存中看到的那样。 不幸的是,这种解决方案具有固有的困难。 特别地,当将空间划分为不同大小的块时, 空间本身可能变得分散,因此 随着时间的推移分配变得更具有挑战性。
因此,第二种方法可能值得考虑:把 空间划分成固定大小的部分。 在虚拟内存中,我们称之为分页, 它来自一个早期重要的系统,Atlas [KE + 62,L78]。 第二种方法不是将进程的地址空间拆分成若干个 可变大小的逻辑段(例如,代码,堆,堆栈),而是将它分成 固定大小的单元,我们每个单元称为页面。 相应地,我们把物理存储看做是由一个许多固定大小的槽的数组,槽也被称为页框。每个页框可以包含一个虚拟内存页。我们的挑战:
如何用页面来虚拟化内存 我们如何用页面虚拟化内存,以避免分段的问题? 什么是基本技术? 我们如何做 这些技术工作得很好,并保证空间和时间开销最小?
为了使这个方法更清楚,让我们用一个简单示例说明。 图18.1展示了一个微小的地址空间的示例, 只有64个字节的大小,有4个16字节的页面(虚拟页0,1,2和3)。 真正的地址空间比这要大得多,通常是32位 的也即4GB的地址空间,甚至是64位的; 在书中,我们经常 本使用微小的例子,使他们更容易消化。
图18.1, 一个简单的64字节地址空间
图18.2, 一个128字节物理内存中的64字节地址空间
物理内存,如图18.2所示,也由许多固定大小的插槽组成,在这种情况下是8个页框(构成一个128字节 物理内存,也是可笑的小)。从图中可以看出, 虚拟地址空间的页已经被放置在物理存储器中的不同位置;该图还显示了OS自己使用 的一些物理内存。
我们将看到分页相比我们的以前的方法有很多优势 。可能最重要的改进将是灵活性:用完全开发的分页方法,系统就能够 支持地址空间的有效抽象,无论如何 进程使用地址空间;例如,我们不会对堆和堆增长的方向和如何使用它们作出任何假设。
另一个优点是分页提供的自由空间管理的简单性。例如,当操作系统希望放置我们的小64字节 物理内存 变成8页的地址空间,它只能找到4个 空闲页面;也许操作系统会保留所有空闲页面的空闲列表,和 只是抓住这个列表前4个可用页面。在示例中,操作系统已将物理帧3中的地址空间(AS)的虚拟页0放置, 物理帧7中的AS的虚拟页1,帧5中的页2和页 3在帧2中。页面帧1,4和6当前是空闲的。
18.1 一个简单的示例及其概述
// Extract the VPN from the virtual address
VPN = (VirtualAddress &VPN_MASK) >> SHIFT;
// Form the address of the page-table entry (PTE)
PTEAddr = PTBR + (VPN *sizeof(PTE));
// Fetch the PTE
PTE = AccessMemory(PTEAddr);
// Check if process can access the page
if (PTE.Valid == False) RaiseException(SEGMENTATION_FAULT);
else if (CanAccess(PTE.ProtectBits) == False)
RaiseException(PROTECTION_FAULT);
else // Access is OK: form physical address and fetch it
offset = VirtualAddress & OFFSET_MASK;
PhysAddr = (PTE.PFN << PFN_SHIFT) | offset;
Register = AccessMemory(PhysAddr);