*3.2.5 抖动和工作集
1. 抖动
在页面置换过程中,最糟糕的情形是:刚刚换出的页面马上又要换入内存,而刚刚换入的页面又立即被换出。这种频繁的页面调度行为称为抖动(也称颠簸)。
系统发生抖动的根本原因在于:分配给进程的物理块数量过少,无法满足其正常运行的基本需求,导致进程在执行过程中频繁触发缺页中断,不得不反复请求系统将所缺页面调入内存。此时,磁盘I/O频率急剧上升,进程的大部分时间都消耗在页面的换入与换出操作上,几乎无法完成有效计算,进而造成CPU利用率急剧下降,甚至趋近于零。
抖动是虚拟存储系统中的严重性能问题,必须加以解决。由于抖动的发生直接源于系统为进程分配的页框数(驻留集)过少,于是又提出了工作集的概念,用以动态指导页框分配。
2. 工作集
工作集是指在某段时间间隔内,进程实际访问过的页面集合。通常,工作集 可由时间 和工作集窗口尺寸共同确定。
在实际应用中,工作集窗口通常设置得较大,对于局部性较好的程序,其工作集大小一般远小于窗口尺寸 。由于工作集反映了进程在随后一段时间内很可能频繁访问的页面集合,因此驻留集的大小不应小于工作集的大小,否则进程在运行过程中将频繁发生缺页。
3.2.6 页框回收
本节为2025年大纲新增考点。实际上,2012年统考真题第45题已涉及页框回收,其将页框回收的过程描述为“被系统回收的页框,放入空闲页框链尾,其中内容在下一次分配之前不清空”,这一描述正是页面缓冲算法中空闲页面链表的定义。因此,本节主要介绍页面缓冲算法。页框回收算法较为复杂,且主流操作系统教材通常未系统介绍相关内容,其细节多见于深入剖析 Linux内核的图书,而408考试中出现的概率也极低,因此本书不做介绍。
1. 页面缓冲算法
在页式虚拟存储系统中,页面换入/换出的开销对系统性能影响显著。
影响页面换入/换出效率的主要因素有如下几种。
页面置换算法的选择。一个好的置换算法可有效降低进程运行过程中的缺页率,从而减少页面换入/换出的频率,显著提升系统性能。已修改页面写回磁盘的频率。对于已被修改的页面(脏页),换出时必须写回磁盘。若采用“每次换出即写回”的策略,则会导致频繁的磁盘I/O操作。磁盘内容读入内存的频率。若每次访问缺失页面都需从磁盘重新读取,则会引发高频率的磁盘I/O,进而增加页面换入的开销。
页面缓冲算法在原页面置换算法的基础上增设一个修改页面链表,保存已修改且需要被换出的页面,等被换出的页面数量达到一定值时,再批量写回磁盘,以减少页面换出的开销。
为显著降低页面换入/换出的频率,系统在内存中维护如下两个专用链表。
空闲页面链表(也称空闲页框链表)。当进程需要读入一个页面时,系统从该链表头部取出一个页框,并将目标页面装入其中。若某未被修改的页面需要被换出,则系统并不将其写回磁盘,而直接将其所在的物理页框挂在空闲链表的末尾。这些页框中仍保留着原有数据。若后续有进程访问相同页面,则可直接从空闲链表中取下该页框复用,从而避免从磁盘重新读入,有效减少页面换入开销。修改页面链表。当进程需要将一个已修改的页面换出时,系统不会立即写回磁盘,而是将其所在的页框挂在该链表的末尾。待链表中积累足够数量的脏页后,再批量写回磁盘。这样不仅降低了写回频率,也减少了因数据缺失而需重新读盘的次数。
上述通过链表管理物理页框、延迟实际I/O的机制,即为页框回收的过程。
页面缓冲算法的优点:
- 显著降低页面换入/换出频率,大幅减少磁盘I/O开销;
- 即使采用简单的置换策略(如FIFO),也能获得良好性能,且无须特殊硬件支持,实现简单高效。
2. 页框回收
当系统可分配的内存不足时,就必须回收部分页框,但并非所有页框都可回收。属于内核的大部分页框(如内核栈、内核代码段、内核数据段、大部分内核使用的页框)均不可回收;而由进程使用的页框(如进程代码段、进程数据段、进程堆栈、进程访问文件时映射的文件页、进程间共享内存所占用的页框)则大多可以回收。
在Linux 内核中,设置了一个负责页面换出的守护进程 kswapd,它定期检查内存使用情况。当空闲页框数量低于特定阈值时,便主动发起页框回收操作。之所以不能等到空闲页框完全耗尽才启动回收,是因为释放某些页框(如脏页)通常需要先将其写回磁盘,而该I/O操作本身往往需要临时页框作为缓冲区。若此时系统已无空闲页框,则既无法分配I/O缓冲区,也无法完成页面释放,从而可能导致内核陷入内存分配死锁,甚至引发系统崩溃。
Linux系统采用3.1.2节介绍的“伙伴算法”对内存中不同长度的连续空闲页框进行统计和管理。该算法将连续的空闲页框组织为“空闲块”,并按其大小(所含连续页框的数量)分组。分配页框是一个“化整为零”的过程,会产生外部碎片;因此,系统必须具备将零碎页框重新合并为较大连续块的能力。Linux 通过伙伴算法的逆操作实现页框回收:当一个页框被释放时,系统首先检查其是否存在大小相等的伙伴空闲块;若存在,则将二者合并为一个大小翻倍的新空闲块;随后继续向上检查该新块是否能与其更高一级的伙伴再次合并,直至无法再合并为止。
3.2.7 内存映射文件
内存映射文件(Memory-Mapped Files)是操作系统向应用程序提供的一种系统调用机制,它在磁盘文件与进程的虚拟地址空间之间建立直接映射关系,与虚拟内存机制紧密相关。
进程通过该系统调用,将一个文件映射到其虚拟地址空间的某一区域,此后便可像访问内存一样读/写文件。这种功能将一个文件当作内存中的一个大字符数组来访问,而无须调用传统的文件I/O接口,显然更为便捷。磁盘文件的读/写由操作系统负责完成,对进程而言是透明的。映射时并不会立即加载文件内容,而是在进程首次访问某页面时,才按需将其一页一页地调入内存;当进程退出或显式解除文件映射时,所有被修改的页面才会被写回磁盘文件。
进程可通过共享内存实现高效通信。实践中,这种共享内存往往正是通过将同一文件映射到多个通信进程的虚拟地址空间来实现的。此时,尽管各进程的虚拟地址空间相互独立,但操作系统会通过页表将它们对应的虚拟页映射到相同的物理页。因此,当一个进程在共享区域执行写操作后,另一个进程在其映射区域执行读操作时,能够立即看到更新结果——因为二者访问的是同一块物理内存,数据必然一致,无须额外的复制或同步机制。
由此可见,内存映射文件带来的好处主要有:
- 使程序员的编程更为简单,已建立映射的文件,可直接按内存方式进行读/写;
- 便于多个进程共享同一个磁盘文件。
3.2.8 虚拟存储器性能影响因素
缺页率是影响虚拟存储器性能的核心因素,而缺页率又受页面大小、分配给进程的物理块数、页面置换算法、写回磁盘的频率以及程序的局部化程度等多方面影响。
根据局部性原理,页面较大时,单次装入可覆盖更多局部访问区域,从而降低缺页率;而页面较小时,缺页率则相对较高。较小的页面虽能减少页内碎片、提高内存利用率,但会导致每个进程所需页面数量增多,导致页表过长,占用大量内存。较大的页面虽可缩短页表长度,却会增大页内碎片。因此,页面大小的设计需在碎片控制与页表开销之间取得合理平衡。
分配给进程的物理块数越多,缺页率通常越低。然而,当物理块数量超过某一阈值后,继续增加块数对缺页率的改善趋于平缓。因为此时进程的活跃页面已基本常驻内存,缺页主要由非活跃页面引发,而这些页面本就无须长期驻留。若再分配更多物理块,则不仅收益甚微,反而造成内存资源浪费。因此,只需确保活跃页面常驻内存,即可将缺页率有效控制在可接受范围内。
好的页面置换算法能有效降低运行过程中的缺页率。例如,LRU、CLOCK等算法通过预测未来访问行为,优先保留可能被再次访问的页面,从而提升内存命中率,加快页面访问速度。
对于已修改的页面(脏页),换出时必须写回磁盘。若采用“每换出一页即写回”的策略,则会频繁触发磁盘I/O,效率极低。为此,系统引入已修改换出页面链表:当脏页被换出时,暂不写回磁盘,而是挂入该链表;待积累足够数量后,再批量写回磁盘,从而显著减少磁盘I/O次数,降低页面换出开销。此外,若某进程在这些页面尚未写回磁盘前再次访问它们,则可直接从链表中复用,无须重新从外存调入,进一步减少页面换入频率与I/O开销。
程序编写的局部化程度越高,执行时的缺页率就越低。例如,若数组采用按行存储,则访问时应尽量按行顺序进行,避免按列访问破坏空间局部性,从而导致缺页率异常升高。
3.2.9 地址翻译的示例
考虑到408统考越来越注重学科综合能力的考查,本节结合《计算机组成原理》中Cache的相关内容,分析虚实地址的变换过程。对于不参加统考的读者,可酌情跳过;对于参加统考但尚未复习该部分内容的读者,建议先完成相关章节的学习,再回过头来学习本节。
设某系统满足以下条件:
- 配置一个TLB和一个 data Cache;
- 存储器以字节为编址单位;
- 虚拟地址为14位;
- 物理地址为12位;
- 页面大小为64B;
- TLB采用四路组相联结构,共16个条目;
- data Cache采用物理寻址、直接映射方式,行大小为4B,共16组。
要求分析对虚拟地址 0x03d4、0x00f1 和 0x0229 的访问过程。
系统以字节编址,页面大小为64B,故页内偏移占 位。虚拟地址共14位,故虚拟页号为 位;物理地址共12位,故物理页号为 位。TLB采用四路组相联,共16个条目,因此组数为 ,组索引占 位,虚拟页号的低2位作为组索引、高6位作为TLB标记。data Cache行大小为4B,故物理地址中最低 位为块内偏移;Cache共16组,因此接下来的 位为组索引,剩余高6位为标记。地址结构如图3.28所示。
WARNING查看书籍确认
图3.28 地址结构
TLB、部分页表及 data Cache的内容分别见表3.1、表3.2和表3.3。
WARNING查看书籍确认
表3.1 TLB
表3.2 部分页表
表3.3 data Cache内容
首先将十六进制的虚拟地址 0x03d4、0x00f1 和 0x0229 转换为二进制形式,如表3.4所示。
表3.4 虚拟地址结构
由表3.4可得各地址的虚拟页号、组索引及TLB标记。接下来需判断对应页面是否已在主存中;若在主存中,则进一步确定其物理地址。
- 对于
0x03d4:组索引为3,TLB标记为0x03。查TLB第3组,存在标记为03且有效位为1的项,TLB命中。对应物理页号为0x0d(001101),拼接页内偏移010100,得物理地址为0x354(001101010100)。 - 对于
0x00f1:组索引为3,TLB标记为0x00。查TLB第3组,无匹配项,TLB未命中,转而查询页表。虚拟页号为0x03,页表第3行有效位为1,表明页面在主存中。物理页号为0x02(000010),拼接页内偏移110001,得物理地址为0x0b1(000010110001)。 - 对于
0x0229:组索引为0,TLB标记为0x02。查TLB第0组,无匹配项。再查页表,虚拟页号为0x08,对应页表项有效位为0,页面不在主存中,触发缺页中断。
获得主存中页面的物理地址后,需通过该地址访问数据,此时应检查其内容是否在Cache中,物理地址结构如表3.5所示。
表3.5 物理地址结构
WARNING查看书籍确认
- 对于
0x354:Cache组索引为5,标记为0x0d。查Cache索引为5的行,标记为0d且有效位为1,Cache命中。偏移为0(块0),故虚拟地址0x03d4对应的数据为36H。 - 对于
0x0b1:Cache组索引为[OCR存疑],标记为0x02。查Cache索引为[OCR存疑]的行,有效位为0,Cache未命中,需从主存中读取物理页号为0x2、偏移为0x31处的数据。
上述示例涵盖了从虚拟地址到Cache查找过程中可能出现的典型情形。完整的地址翻译与数据访问流程如下:首先查询TLB;若TLB未命中,则需访问页表以完成虚实地址转换。在此过程中,若发现所需页面尚未调入主存(页表项无效),则触发缺页中断,从外存调入该页面。随后,利用所得物理地址访问Cache;若Cache未命中,则进一步从主存读取所需数据。
3.2.10 本节小结
本节开头提出的问题的参考答案如下。
-
为什么要引入虚拟内存?
上一节提到,多道程序并发执行使进程共享处理器和内存。随着并发进程数量的增加,每个进程获得的处理器时间会相对平滑地减少;然而,若同时运行的进程过多,则内存需求将急剧上升,当某个进程无法获得足够的内存时,甚至无法被加载运行。因此,在物理内存扩展受限的情况下,有必要通过其他方式在逻辑上扩充内存容量,虚拟内存技术由此应运而生。
-
虚拟内存(虚存)空间的大小由什么因素决定?
虚拟内存空间的大小主要由虚拟地址的位数决定。例如,若虚拟地址为32位,且存储器按字节编址,则虚存空间最大为 ,即4GB。系统试图定义超过4GB的虚拟地址空间时,由于32位地址最多只能寻址4GB,超出部分将无法被访问。
-
虚拟内存是怎么解决问题的?会带来什么问题?
虚拟内存利用外存空间在逻辑上扩充内存容量,通过页面的换入/换出机制,使系统能够运行总规模远超物理内存的多个进程。然而,该机制也引入额外开销:每次缺页均需访问外存,导致平均访存时间增加;采用不合适的页面置换算法,还可能引发频繁缺页,降低系统性能。
本节学习了4种页面置换算法,要将它们与处理机调度算法区分开。当然,二者存在内在联系:它们都属于资源调度机制,核心思想是依据某种准则,决定将有限资源分配给哪个请求者。处理机调度的准则包括优先级、响应比、时间片等;而页面置换则聚焦于页面的使用历史,如是否被访问过、近期是否经常使用。事实上,操作系统中几乎每类资源都有相应的调度策略。读者若能以“调度”为线索串联各类算法,则有助于构建对操作系统整体架构的系统性理解。
