为什么我们要为进程支持巨大的地址空间?

字数 4144阅读 45

本文内容摘自《操作系统导论》第21节部分内容。

到目前为止,我们一直假定地址空间非常小,能放入物理内存。事实上,我们假设每个正在运行的进程的地址空间都能放入内存。我们将放松这些大的假设,并假设我们需要支持许多同时运行的巨大地址空间。

为了达到这个目的,需要在内存层级(memory hierarchy)上再加一层。到目前为止,我们一直假设所有页都常驻在物理内存中。但是,为了支持更大的地址空间,操作系统需要把当前没有在用的那部分地址空间找个地方存储起来。一般来说,这个地方有一个特点,那就是比内存有更大的容量。因此,一般来说也更慢(如果它足够快,我们就可以像使用内存一样使用,对吗?)。在现代系统中,硬盘(hard disk drive)通常能够满足这个需求。因此,在我们的存储层级结构中,大而慢的硬盘位于底层,内存之上。那么我们的关键问题是:

关键问题:如何超越物理内存

操作系统如何利用大而慢的设备,透明地提供巨大虚拟地址空间的假象?

你可能会问一个问题:为什么我们要为进程支持巨大的地址空间?答案还是方便和易用性。有了巨大的地址空间,你不必担心程序的数据结构是否有足够空间存储,只需自然地编写程序,根据需要分配内存。这是操作系统提供的一个强大的假象,使你的生活简单很多。别客气!一个反面例子是,一些早期系统使用“内存覆盖(memory overlays)”,它需要程序员根据需要手动移入或移出内存中的代码或数据[D97]。设想这样的场景:在调用函数或访问某些数据之前,你需要先安排将代码或数据移入内存。

补充:存储技术

稍后将深入介绍I/O设备如何运行。所以少安毋躁!当然,这个较慢的设备可以是硬盘,也可以是一些更新的设备,比如基于闪存的SSD。我们也会讨论这些内容。但是现在,只要假设有一个大而较慢的设备,可以利用它来构建巨大虚拟内存的假象,甚至比物理内存本身更大。

不仅是一个进程,增加交换空间让操作系统为多个并发运行的进程都提供巨大地址空间的假象。多道程序(能够“同时”运行多个程序,更好地利用机器资源)的出现,强烈要求能够换出一些页,因为早期的机器显然不能将所有进程需要的所有页同时放在内存中。因此,多道程序和易用性都需要操作系统支持比物理内存更大的地址空间。这是所有现代虚拟内存系统都会做的事情,也是现在我们要进一步学习的内容。

21.1 交换空间

我们要做的第一件事情就是,在硬盘上开辟一部分空间用于物理页的移入和移出。在操作系统中,一般这样的空间称为交换空间(swap space),因为我们将内存中的页交换到其中,并在需要的时候又交换回去。因此,我们会假设操作系统能够以页大小为单元读取或者写入交换空间。为了达到这个目的,操作系统需要记住给定页的硬盘地址(disk address)。

交换空间的大小是非常重要的,它决定了系统在某一时刻能够使用的最大内存页数。简单起见,现在假设它非常大。

在小例子中(见图21.1),你可以看到一个4页的物理内存和一个8页的交换空间。在这个例子中,3个进程(进程0、进程1和进程2)主动共享物理内存。但3个中的每一个,都只有一部分有效页在内存中,剩下的在硬盘的交换空间中。第4个进程(进程3)的所有页都被交换到硬盘上,因此很清楚它目前没有运行。有一块交换空间是空闲的。即使通过这个小例子,你应该也能看出,使用交换空间如何让系统假装内存比实际物理内存更大。

我们需要注意,交换空间不是唯一的硬盘交换目的地。例如,假设运行一个二进制程序(如ls,或者你自己编译的main程序)。这个二进制程序的代码页最开始是在硬盘上,但程序运行的时候,它们被加载到内存中(要么在程序开始运行时全部加载,要么在现代操作系统中,按需要一页一页加载)。但是,如果系统需要在物理内存中腾出空间以满足其他需求,则可以安全地重新使用这些代码页的内存空间,因为稍后它又可以重新从硬盘上的二进制文件加载。

图21.1 物理内存和交换空间

21.2 存在位

现在我们在硬盘上有一些空间,需要在系统中增加一些更高级的机制,来支持从硬盘交换页。简单起见,假设有一个硬件管理TLB的系统。

先回想一下内存引用发生了什么。正在运行的进程生成虚拟内存引用(用于获取指令或访问数据),在这种情况下,硬件将其转换为物理地址,再从内存中获取所需数据。

硬件首先从虚拟地址获得VPN,检查TLB是否匹配(TLB命中),如果命中,则获得最终的物理地址并从内存中取回。这希望是常见情形,因为它很快(不需要额外的内存访问)。

如果在TLB中找不到VPN(即TLB未命中),则硬件在内存中查找页表(使用页表基址寄存器),并使用VPN查找该页的页表项(PTE)作为索引。如果页有效且存在于物理内存中,则硬件从PTE中获得PFN,将其插入TLB,并重试该指令,这次产生TLB命中。到现在为止还挺好。

但是,如果希望允许页交换到硬盘,必须添加更多的机制。具体来说,当硬件在PTE中查找时,可能发现页不在物理内存中。硬件(或操作系统,在软件管理TLB时)判断是否在内存中的方法,是通过页表项中的一条新信息,即存在位(present bit)。如果存在位设置为1,则表示该页存在于物理内存中,并且所有内容都如上所述进行。如果存在位设置为零,则页不在内存中,而在硬盘上。访问不在物理内存中的页,这种行为通常被称为页错误(page fault)。

补充:交换术语及其他

对于不同的机器和操作系统,虚拟内存系统的术语可能会有点令人困惑和不同。例如,页错误(page fault)一般是指对页表引用时产生某种错误:这可能包括在这里讨论的错误类型,即页不存在的错误,但有时指的是内存非法访问。事实上,我们将这种完全合法的访问(页被映射到进程的虚拟地址空间,但此时不在物理内存中)称为“错误”是很奇怪的。实际上,它应该被称为“页未命中(page miss)”。但是通常,当人们说一个程序“页错误”时,意味着它正在访问的虚拟地址空间的一部分,被操作系统交换到了硬盘上。

我们怀疑这种行为之所以被称为“错误”,是因为操作系统中的处理机制。当一些不寻常的事情发生的时候,即硬件不知道如何处理的时候,硬件只是简单地把控制权交给操作系统,希望操作系统能够解决。在这种情况下,进程想要访问的页不在内存中。硬件唯一能做的就是触发异常,操作系统从开始接管。由于这与进程执行非法操作处理流程一样,所以我们把这个活动称为“错误”,这也许并不奇怪。

在页错误时,操作系统被唤起来处理页错误。一段称为“页错误处理程序(page-fault handler)”的代码会执行,来处理页错误,接下来就会讲。

21.3 页错误

回想一下,在TLB未命中的情况下,我们有两种类型的系统:硬件管理的TLB(硬件在页表中找到需要的转换映射)和软件管理的TLB(操作系统执行查找过程)。不论在哪种系统中,如果页不存在,都由操作系统负责处理页错误。操作系统的页错误处理程序(page-fault handler)确定要做什么。几乎所有的系统都在软件中处理页错误。即使是硬件管理的TLB,硬件也信任操作系统来管理这个重要的任务。

如果一个页不存在,它已被交换到硬盘,在处理页错误的时候,操作系统需要将该页交换到内存中。那么,问题来了:操作系统如何知道所需的页在哪儿?在许多系统中,页表是存储这些信息最自然的地方。因此,操作系统可以用PTE中的某些位来存储硬盘地址,这些位通常用来存储像页的PFN这样的数据。当操作系统接收到页错误时,它会在PTE中查找地址,并将请求发送到硬盘,将页读取到内存中。

补充:为什么硬件不能处理页错误 

我们从TLB的经验中得知,硬件设计者不愿意信任操作系统做所有事情。那么为什么他们相信操作系统来处理页错误呢?有几个主要原因。首先,页错误导致的硬盘操作很慢。即使操作系统需要很长时间来处理故障,执行大量的指令,但相比于硬盘操作,这些额外开销是很小的。其次,为了能够处理页故障,硬件必须了解交换空间,如何向硬盘发起I/O操作,以及很多它当前所不知道的细节。因此,由于性能和简单的原因,操作系统来处理页错误,即使硬件人员也很开心。

当硬盘I/O完成时,操作系统会更新页表,将此页标记为存在,更新页表项(PTE)的PFN字段以记录新获取页的内存位置,并重试指令。下一次重新访问TLB还是未命中,然而这次因为页在内存中,因此会将页表中的地址更新到TLB 中(也可以在处理页错误时更新TLB以避免此步骤)。最后的重试操作会在TLB 中找到转换映射,从已转换的内存物理地址,获取所需的数据或指令。

请注意,当I/O在运行时,进程将处于阻塞(blocked)状态。因此,当页错误正常处理时,操作系统可以自由地运行其他可执行的进程。因为I/O操作是昂贵的,一个进程进行I/O(页错误)时会执行另一个进程,这种交叠(overlap)是多道程序系统充分利用硬件的一种方式。

21.4 内存满了怎么办

在上面描述的过程中,你可能会注意到,我们假设有足够的空闲内存来从存储交换空间换入(page in)的页。当然,情况可能并非如此。内存可能已满(或接近满了)。因此,操作系统可能希望先交换出(page out)一个或多个页,以便为操作系统即将交换入的新页留出空间。选择哪些页被交换出或被替换(replace)的过程,被称为页交换策略(page-replacement policy)。

事实表明,人们在创建好页交换策略上投入了许多思考,因为换出不合适的页会导致程序性能上的巨大损失,也会导致程序以类似硬盘的速度运行而不是以类似内存的速度。在现有的技术条件下,这意味着程序可能会运行慢10000~100000倍。因此,这样的策略是我们应该详细研究的。实际上,这也正是我们下一章要做的。现在,我们只要知道有这样的策略存在,建立在之前描述的机制之上。

操作系统导论

作者:[美] 雷姆兹·H.阿帕希杜塞尔( Remzi H. Arpaci-Dusseau), [美]安德莉亚·C.阿帕希杜塞尔(Andrea C. Arpaci-Dusseau)

译者:王海鹏

美国知名操作系统教材

紧紧围绕操作系统的三大主题元素:虚拟化 并发和持久性进行讲解

豆瓣原版评分9.7

本书围绕虚拟化、并发和持久性这三个主要概念展开,介绍了所有现代系统的主要组件(包括调度、虚拟内存管理、磁盘和I/O子系统、文件系统)。全书共50章,分为3个部分,分别讲述虚拟化、并发和持久性的相关内容。作者以对话形式引入所介绍的主题概念,行文诙谐幽默却又鞭辟入里,力求帮助读者理解操作系统中虚拟化、并发和持久性的原理。

本书内容全面,并给出了真实可运行的代码(而非伪代码),还提供了相应的练习,很适合高等院校相关专业的教师开展教学和高校学生进行自学。

本书具有以下特色:

● 主题突出,紧紧围绕操作系统的三大主题元素——虚拟化、并发和持久性。

● 以对话的方式引入背景,提出问题,进而阐释原理,启发动手实践。

● 包含众多“补充”和“提示”,拓展读者知识面,增加趣味性。

● 使用真实代码而不是伪代码,让读者更加深入透彻地了解操作系统。

● 提供作业、模拟和项目等众多学习方式,鼓励读者动手实践。

● 为教师提供教学辅助资源。

推荐阅读更多精彩内容