• 第 3 章 内存管理

    Intro

    【考纲内容】

    (一)内存管理基础 内存管理概念:逻辑地址与物理地址空间,地址变换,内存共享,内存保护,内存分配与回收连续分配管理方式;页式管理;段式管理;段页式管理.、视频讲解

    (二)虚拟内存 管理虚拟内存基本概念;请求页式管理;页框分配;页置换算法 内存映射文件(Memory-Mapped Files):虚拟存储器性能的影响因素及改进方式

    【复习提示】

    内存管理和进程管理是操作系统的核心内容,需要重点复习。本章围绕分页机制展开:通过分页管理方式在物理内存大小的基础上提高内存的利用率,再进一步引入请求分页管理方式,实现虚拟内存,使内存脱离物理大小的限制,从而提高处理器的利用率。

    一、内存管理概念

    0x00 内存管理的基本原理和要求

    内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之-一。虽然计算机硬件技术一直在飞速发展,内存容量也在不断增大,但仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主存,因此操作系统必须对内存空间进行合理的划分和有效的动态分配。操作系统对内存的划分和动态分配,就是内存管理的概念。

    有效的内存管理在多道程序设计中非常重要,它不仅可以方便用户使用存储器、提高内存利用率,还可以通过虚拟技术从逻辑上扩充存储器。

    内存管理的主要功能有:

    在进行具体的内存管理之前,需要了解进程运行的基本原理和要求。

     

    1. 程序的链接与装入

    创建进程首先要将程序和数据装入内存。将用户源程序变为可在内存中执行的程序,通常需要以下几个步骤:

    这三步过程如图3.1所示。

    1

    程序的链接有以下三种方式。

    1. 静态链接 在程序运行之前,先将各目标模块及它们所需的库函数链接成一个完整的装配模块,以后不再拆开。将几个目标模块装配成一个装入模块时,需要解决两个问题: ①修改相对地址,编译后部调用符号,将每个模块中所用的外部调用符号也都变换为相对地址。 ②变换外部调用符号,将每个模块中所用的外部调用符号也都变为相对地址
    2. 装入时动态链接 将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的方式。其优点是便于修改和更新,便于实现对目标模块的共享。
    3. 运行时动态链接 对某些目标模块的链接,是在程序执行中需要该目标模块时才进行的。凡在执行过程中未被用到的目标模块,都不会被调入内存和被链接到装入模块上。其优点是能加快程序的装入过程,还可节省大量的内存空间。

    内存的装入模块在装入内存时,同样有以下三种方式:

    1. 绝对装入 绝对装入方式只适用于单道程序环境。在编译时,若知道程序将驻留在内存的某个位置,则编译程序将产生绝对地址的目标代码。绝对装入程序按照装入模块中的地址,将程序和数据装入内存。由于程序中的逻辑地址与实际内存地址完全相同,因此不需对程序和数据的地址进行修改。 另外,程序中所用的绝对地址,可在编译或汇编时给出,也可由程序员直接赋予。而通常情况下在程序中采用的是符号地址,编译或汇编时再转换为绝对地址。
    2. 可重定位装入 在多道程序环境下,多个目标模块的起始地址通常都从0开始,程序中的其他地址都是相对于起始地址的,此时应采用可重定位装入方式。根据内存的当前情况,将装入模块装入内存的适当位置。在装入时对目标程序中指令和数据地址的修改过程称为重定位,又因为地址变换通常是在进程装入时一次完成的,故称为静态重定位,如图3.2(a)所示。 当一个作业装入内存时,必须给它分配要求的全部内存空间,若没有足够的内存,则无法装入。此外,作业一旦进入内存,整个运行期间就不能在内存中移动,也不能再申请内存空间。
    3. 动态运行时装入 也称动态重定位。程序在内存中若发生移动,则需要采用动态的装入方式。装入程序把装入模块装入内存后,并不立即把装入模块中的相对地址转换为绝对地址,而是把这种地址转换推迟到程序真正要执行时才进行。因此,装入内存后的所有地址均为相对地址。这种方式需要一个重定位寄存器的支持,如图3.2(b)所示。 动态重定位的优点:可以将程序分配到不连续的存储区;在程序运行之前可以只装入部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享。

    2

    考虑了一些不具有位置无关性的程序能够正确运行的保障

    2. 逻辑地址与物理地址

    编译后,每个目标模块都从0号单元开始编址,这称为该目标模块的相对地址(或逻辑地址)。当链接程序将各个模块链接成一个完整的可执行目标程序时,链接程序顺序依次按各个模块的相对地址构成统一的从0号单元开始编址的逻辑地址空间或虚拟地址空间),对于32位系统,逻辑地址空间的范围为 0~232-1。进程在运行时,看到和使用的地址都是逻辑地址。用户程序和程址,因为这些相同的逻辑地址可以映射到主存的不同位置。

    物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址,进程在运行时执行指令和访问数据,最后都要通过物理地址从主存中存取。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位

    操作系统通过内存管理部件(MMU)将进程使用的逻辑地址转换为物理地址。进程使用虚拟内存空间中的地址,操作系统在相关硬件的协助下,将它“转换”成真正的物理地址。逻辑地址通过页表映射到物理内存,页表由操作系统维护并被处理器引用。

    3. 进程的内存

    不同于存放在硬盘上的可执行程序文件,当一个程序调入内存运行时,就构成了进程的内存映像。一个进程的内存映像一般有几个要素:

    代码段和数据段在程序调入内存时就指定了大小,而堆和栈不一样。当调用像 malloc 和 free这样的C标准库函数时,堆可以在运行时动态地扩展和收缩。用户栈在程序运行期间也可以动态地扩展和收缩,每次调用一个函数,栈就会增长;从一个函数返回时,栈就会收缩。

    图3.3是一个进程在内存中的映像。其中,共享库用来存放进程用到的共享函数库代码,如 printf() 函数等。在只读代码段中,.init 是程序初始化时调用的_init 函数;.text 是用户程序的机器代码;.rodata 是只读数据。在读/写数据段中,.data 是已初始化的全局变量和静态变量;.bss 是未初始化及所有初始化为0的全局变量和静态变量。

    3

    4. 内存保护

    确保每个进程都有一个单独的内存空间。内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。内存保护可采取两种方法:

    1)在CPU中设置一对上、下限寄存器,存放用户作业在主存中的下限和上限地址,每当CPU要访问一个地址时,分别和两个寄存器的值相比,判断有无越界。

    2)采用重定位寄存器(又称基地址寄存器)和界地址寄存器(又称限长寄存器)来实现这种保护。重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址的最大值。内存管理机构动态地将逻辑地址与界地址寄存器进行比较,若未发生地址越界,则加上重定位寄存器的值后映射成物理地址,再送交内存单元,如图3.4所示。

    4

    实现内存保护需要重定位寄存器和界地址寄存器,因此要注意两者的区别。重定位寄存器是用来“加”的,逻辑地址加上重定位寄存器中的值就能得到物理地址;界地址寄存器是用来“比”的,通过比较界地址寄存器中的值与逻辑地址的值来判断是否越界。

    加载重定位寄存器和界地址寄存器时必须使用特权指令,只有操作系统内核才可以加载这两个存储器。这种方案允许操作系统内核修改这两个寄存器的值,而不允许用户程序修改。

    5. 内存共享

    并不是所有的进程内存空间都适合共享,只有那些只读的区域才可以共享。可重入代码又称纯代码,是一种允许多个进程同时访问但不允许被任何进程修改的代码。但在实际执行时,也可以为每个进程配以局部数据区,把在执行中可能改变的部分复制到该数据区,这样,程序在执行时只需对该私有数据区中的内存进行修改,并不去改变共享的代码。

    下面通过一个例子来说明内存共享的实现方式。考虑一个可以同时容纳40个用户的多用户系统,他们同时执行一个文本编辑程序,若该程序有 160KB 代码区和 40KB 数据区,则共需 8000 KB 的内存空间来支持40个用户。如果160KB代码是可分享的纯代码,则不论是在分页系统中还是在分段系统中,整个系统只需保留一份副本即可,此时所需的内存空间仅为40KB×40+160KB=1760KB。对于分页系统,假设页面大小为4KB,则代码区占用40个页面、数据区占用10个页面。为实现代码共享,应在每个进程的页表中都建立,40个页表项,它们都指向共享代码区的物理页号。此外,每个进程还要为自己的数据区建立10个页表项,指向私有数据区的物理页号。向共享代码段始址,以及段长160KB)。由此可见,段的共享非常简单易行。

    此外,在第2章中我们介绍过基于共享内存的进程通信,由操作系统提供同步互斥工具。在本章的后面,还将介绍一种内存共享的实现一一内存映射文件。

    6. 内存分配与回收

    存储管理方式随着操作系统的发展而发展。在操作系统由单道向多道发展时,存储管理方式便由单一连续分配发展为固定分区分配。为了能更好地适应不同大小的程序要求,又从固定分区分配发展到动态分区分配。为了更好地提高内存的利用率,进而从连续分配方式发展到离散分配方式一一页式存储管理。引入分段存储管理的目的,主要是为了满足用户在编程和使用方面的要求,其中某些要求是其他几种存储管理方式难以满足的。

     

    0x01 覆盖与交换(在新大纲中已删除)

    覆盖与交换技术是在多道程序环境下用来扩充内存的两种方法。

    1. 覆盖

    早期的计算机系统中,主存容量很小,虽然主存中仅存放一道用户程序,但存储空间放不下用户进程的现象也经常发生,这一矛盾可以用覆盖技术来解决。

    覆盖的基本思想如下:由于程序运行时并非任何时候都要访问程序及数据的各个部分(尤其是大程序),因此可把用户空间分成一个固定区和若干覆盖区。将经常活跃的部分放在固定区,其余部分按调用关系分段。首先将那些即将要访问的段放入覆盖区,其他段放在外存中,在需要调用前,系统再将其调入覆盖区,替换覆盖区中原有的段。

    覆盖技术的特点是,打破了必须将一个进程的全部信息装入主存后才能运行的限制,但当同时运行程序的代码量大于主存时仍不能运行,此外,内存中能够更新的地方只有覆盖区的段,不在覆盖区中的段会常驻内存。覆盖技术对用户和程序员不透明。

    2. 交换

    交换(对换)的基本思想是,把处于等待状态(或在CPU调度原则下被剥夺运行权利)的程序从内存移到辅存,把内存空间腾出来,这一过程又称换出;把准备好竞争 CPU 运行的程序从辅存移到内存,这一过程又称换入。第2章介绍的中级调度采用的就是交换技术

    例如,有一个CPU采用时间片轮转调度算法的多道程序环境。时间片到,内存管理器将刚刚执行过的进程换出,将另一进程换入刚刚释放的内存空间。同时,CPU调度器可以将时间片分配给其他已在内存中的进程。每个进程用完时间片都与另一进程交换。在理想情况下,内存管理器的交换过程速度足够快,总有进程在内存中可以执行。

    有关交换,需要注意以下几个问题:

    交换技术主要在不同进程(或作业)之间进行,而覆盖则用于同一个程序或进程中。对于主存无法存放用户程序的矛盾,现代操作系统是通过虚拟内存技术来解决的,覆盖技术则已成为历史;而交换技术在现代操作系统中仍具有较强的生命力。

     

    0x02 连续分配管理方式

    连续分配方式是指为一个用户程序分配一个连续的内存空间,譬如某用户需要100MB的内存空间,连续分配方式就在内存空间中为用户分配一块连续的100MB空间。连续分配方式主要包括单一连续分配固定分区分配动态分区分配

    1. 单一连续分配

    内存在此方式下分为系统区和用户区,系统区仅供操作系统使用,通常在低地址部分;在用户区内存中,仅有一道用户程序,即整个内存的用户空间由该程序独占

    这种方式的优点是简单、无外部碎片,无须进行内存保护,因为内存中永远只有一道程序。缺点是只能用于单用户、单任务的操作系统中,有内部碎片,存储器的利用率极低。

    2. 固定分区分配

    固定分区分配是最简单的一种多道程序存储管理方式,它将用户内存空间划分为若干固定大小的区域,每个分区只装入一道作业。当有空闲分区时,便可再从外存的后备作业队列中选择适当大小的作业装入该分区,如此循环。在划分分区时有两种不同的方法。

    为了便于分配,建立一张分区使用表,通常按分区大小排队,各表项包括每个分区的起始地址、大小及状态(是否已分配),如图3.5所示。分配内存时,便检索该表,以找到一个能满足要求且尚未分配的分区分配给装入程序,并将对应表项的状态置为“已分配”;若找不到这样的分区,则拒绝分配。回收内存时,只需将对应表项的状态置为“未分配”即可。

    5

    这种方式存在两个问题: 一是程序可能太大而放不进任何一个分区,这是就需要采用覆盖技术来使用内存空间; 二是当程序小于固定分区大小时,也要占用一个完整的内存分区,这样分区内部就存在空间浪费,这种现象称为内部碎片 固定分区是可用于多道程序设计的最简单的存储分配,无外部碎片,但不能实现多进程共享一个主存区,所以存储空间利用率低。

    3. 动态分区分配

    又称可变分区分配,它是在进程装入内存时,根据进程的实际需要,动态地为之分配内存,并使分区的大小正好适合进程的需要。因此,系统中分区的大小和数目是可变的。

    如图3.6所示,系统有 64MB 内存空间,其中低 8MB 固定分配给操作系统,其余为用户可用内存。开始时装入前三个进程,它们分别分配到所需的空间后,内存仅剩4MB,进程4无法装入。在某个时刻,内存中没有一个就绪进程,CPU 出现空闲,操作系统就换出进程2,换入进程4。由于进程4 比进程2小,这样在主存中就产生了一个6MB的内存块。之后CPU又出现空闲,需要换入进程2,而主存无法容纳进程2,操作系统就换出进程1,换入进程2。

    动态分区在开始时是很好的,但随着时间的推移,内存中会产生越来越多小的内存块,内存的利用率也随之下降。这些小的内存块称为外部碎片,它存在于所有分区的外部,这与固定分区中的内部碎片正好相对。克服外部碎片可以通过紧凑技术来解决,即操作系统不时地对进程进行移动和整理。但这需要动态重定位寄存器的支持,且相对费时。紧凑的过程实际上类似于Windows系统中的磁盘碎片整理程序,只不过后者是对外存空间的紧凑。

    6

    在进程装入或换入主存时,若内存中有多个足够大的空闲块,则操作系统必须确定分配哪个内存块给进程使用,这就是动态分区的分配策略。考虑以下几种算法:

    1. 首次适应(First Fit)算法。空闲分区以地址递增的次序链接。分配内存时,从链首开始顺序查找,找到大小能满足要求的第一个空闲分区分配给作业。
    2. 邻近适应(Next Fit)算法。又称循环首次适应算法,由首次适应算法演变而成。不同之处是,分配内存时从上次查找结束的位置开始继续查找。
    3. 最佳适应(Best Fit)算法。空闲分区按容量递增的次序形成空闲分区链,找到第一个能满足要求且最小的空闲分区分配给作业,避免“大材小用”。
    4. 最坏适应(Worst Fit)算法。空闲分区以容量递减的次序链接,找到第一个能满足要求的,即最大的分区,从中分割一部分存储空间给作业。

    首次适应算法最简单,通常也是最好和最快的。不过,首次适应算法会使得内存的低地址部分出现很多小的空闲分区,而每次分配查找时都要经过这些分区,因此增加了开销。

    邻近适应算法试图解决这个问题。但它常常导致在内存空间的尾部(因为在一遍扫描中,内存前面部分使用后再释放时,不会参与分配)分裂成小碎片。通常比首次适应算法要差。

    最佳适应算法虽然称为“最佳”,但是性能通常很差,因为每次最佳的分配会留下很小的难以利用的内存块,会产生最多的外部碎片。

    最坏适应算法与最佳适应算法相反,它选择最大的可用块,这看起来最不容易产生碎片,但是却把最大的连续内存划分开,会很快导致没有可用的大内存块,因此性能也非常差。

    在动态分区分配中,与固定分区分配类似,设置一张空闲分区链(表),并按始址排序。分配内存时,检索空闲分区链,找到所需的分区,若其大小大于请求大小,便从该分区中按请求大小分割一块空间分配给装入进程(若剩余部分小到不足以划分,则无须分割),余下部分仍留在空闲分区链中。回收内存时,系统根据回收分区的始址,从空闲分区链中找到相应的插入点,此时可能出现四种情况:

    1. 回收区与插入点的前一空闲分区相邻,将这两个分区合并,并修改前一分区表项的大小为两者之和;
    2. 回收区与插入点的后一空闲分区相邻,将这两个分区合并,并修改后一分区表项的始址和大小;
    3. 回收区同时与插入点的前、后两个分区相邻,此时将这三个分区合并,修改前一分区表项的大小为三者之和,取消后一分区表项;
    4. 回收区没有相邻的空闲分区,此时应为回收区新建一个表项,填写始址和大小,并插入空闲分区链。

    以上三种内存分区管理方法有一个共同特点,即用户程序在主存中都是连续存放的。

    在连续分配方式中,我们发现,即使内存有超过1GB 的空闲空间,但若没有连续的1GB空间,则需要1GB空间的作业仍然是无法运行的;但若采用非连续分配方式,则作业所要求的1GB内存空间可以分散地分配在内存的各个区域,当然,这也需要额外的空间去存储它们(分散区域)的索引,使得非连续分配方式的存储密度低于连续分配方式。

    非连续分配方式根据分区的大小是否固定,分为分页存储管理和分段存储管理。在分页存储管理中,又根据运行作业时是否要把作业的所有页面都装入内存才能运行,分为基本分页存储管理和请求分页存储管理。

    与 ptmalloc2 有所不同: ptmalloc2 用于堆内存的管理,这里则是进程分配内存的管理 ptmalloc2 各 bin 的链表未必按照始址排序,而是有更复杂的规律,而这里的空闲链表则是按始址排序的。然而,在具体的题目中,即使未特殊标记,却往往是按空闲块大小进行升序排列,怎么回事呢?

    0x03 基本分页存储管理

    固定分区会产生内部碎片,动态分区会产生外部碎片,这两种技术对内存的利用率都比较低。我们希望内存的使用能尽量避免碎片的产生,这就引入了分页的思想:把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位。每个进程也以块为单位进行划分,进程在执行时,以块为单位逐个申请主存中的块空间。

    分页的方法从形式上看,像分区相等的固定分区技术,分页管理不会产生外部碎片。但它又有本质的不同点:块的大小相对分区要小很多,而且进程也按照块进行划分,进程运行时按块申请主存可用空间并执行。这样,进程只会在为最后一个不完整的块申请一个主存块空间时,才产生主存碎片,所以尽管会产生内部碎片,但这种碎片相对于进程来说也是很小的,每个进程平均只产生半个块大小的内部碎片(也称页内碎片)

    1. 分页存储的几个基本概念

    (1) 页面和页面大小

    进程中的块称为页面(Page),内存中的块称为页框页帧(Page Frame)。外存也以同样的单位进行划分,直接称为盘块(Block)。进程在执行时需要申请主存空间,即要为每个页面分配主存中的可用页框,这就产生了页和页框的一一对应。

    为方便地址转换,页面大小应是2的整数幂。同时页面大小应该适中, 页面太小会使进程的页面数过多,这样页表就会过长,占用大量内存,而且也会增加硬件地址转换的开销,降低页面换入/换出的效率; 页面过大又会使页内碎片增多,降低内存的利用率。

    (2) 地址结构

    分页存储管理的逻辑地址结构如图3.7所示。

    7

    地址结构包含两部分:前一部分为页号 P,后一部分为页内偏移量 W。地址长度为 32 位,其中 0~11 位为页内地址,即每页大小为 4KB;12~31 位为页号,即最多允许 220 页。

    注意,地址结构决定了虚拟内存的寻址空间有多大。在实际问题中,页号、页内偏移、逻辑地址可能是用十进制数给出的,若题目用二进制地址的形式给出时,读者要会转换。

    (3) 页表

    为了便于在内存中找到进程的每个页面所对应的物理块,系统为每个进程建立一张页表,它记录页面在内存中对应的物理块号,页表一般存放在内存中。

    在配置页表后,进程执行时,通过查找该表,即可找到每页在内存中的物理块号。可见,页表的作用是实现从页号到物理块号的地址映射,如图3.8所示。

    页表是由页表项组成的,初学者容易混淆页表项与地址结构,页表项与地址都由两部分构成而且第一部分都是页号,但页表项的第二部分是物理内存中的块号,而地址的第二部分是页内偏移;页表项的第二部分与地址的第二部分共同组成物理地址。

    8

    2. 基本地址变换机构

    地址变换机构的任务是将逻辑地址转换为内存中的物理地址。地址变换是借助于页表实现的。图3.9给出了分页存储管理系统中的地址变换机构。

    9

    在系统中通常设置一个页表寄存器(PTR),存放页表在内存的起始地址 F 和页表长度 M。平时,进程未执行时,页表的始址和页表长度存放在本进程的PCB 中,当进程被调度执行时,才将页表始址和页表长度装入页表寄存器中。设页面大小为 L,逻辑地址A 到物理地址E的变换过程如下(假设逻辑地址、页号、每页的长度都是十进制数):

    1. 计算页号 P(P=A/L)和页内偏移量 W(W=A%L)。
    2. 比较页号 P 和页表长度 M,若 PM ,则产生越界中断,否则继续执行。
    3. 页表中 P=F+P×,取出该页表项内容 b,即为物理块号。注意区分页表长度和页表项长度。页表长度是指一共有多少页,页表项长度是指页地址占多大的存储空间。
    4. 计算 E=b×L+W,用得到的物理地址E去访问内存。

    以上整个地址变换过程均是由硬件自动完成的。例如,若页面大小 L 为1KB,页号 2 对应的物理块为 b = 8,计算逻辑地址 A = 2500 的物理地址 E 的过程如下:P=2500/1K=2,W=2500%1K=452,查找得到页号 2 对应的物理块的块号为 8,E=8×1024+452=8644

    计算条件用十进制数和用二进制数给出,过程会稍有不同。页式管理只需给出一个整数就能确定对应的物理地址,因为页面大小L是固定的。因此,页式管理中地址空间是一维的。

    页表项的大小不是随意规定的,而是有所约束的。如何确定页表项的大小?

    页表项的作用是找到该页在内存中的位置。以32位逻辑地址空间、字节编址单位、一页 4KB为例,地址空间内一共有 232B/4KB=1M 页,因此需要 log21M=20 位才能保证表示范围能容纳所有页面,又因为以字节作为编址单位,即页表项的大小 20/8=3B 。所以在这个条件下,为了保证页表项能够指向所有页面,页表项的大小应该大于或等于3B,当然,也可选择更大的页表项让一个页面能够正好容下整数个页表项,进而方便存储(如取成 4B,这样一页正好可以装下 1K 个页表项),或增加一些其他信息。

    下面讨论分页管理方式存在的两个主要问题: ①每次访存操作都需要进行逻辑地址到物理地址的转换,地址转换过程必须足够快,否则访存速度会降低; ②每个进程引入页表,用于存储映射机制,页表不能太大,否则内存利用率会降低。

     

    3. 具有快表的地扯变换机构

    由上面介绍的地址变换过程可知,若页表全部放在内存中,则存取一个数据或一条指令至少要访问两次内存:第一次是访问页表,确定所存取的数据或指令的物理地址;第二次是根据该地址存取数据或指令。显然,这种方法比通常执行指令的速度慢了一半。

    为此,在地址变换机构中增设一个具有并行查找能力的高速缓冲存储器一一快表,又称相联存储器(TLB),用来存放当前访问的若干页表项,以加速地址变换的过程。与此对应,主存中的页表常称为慢表。具有快表的地址变换机构如图3.10 所示。

    10

    在具有快表的分页机制中,地址的变换过程如下:

    1. CPU 给出逻辑地址后,由硬件进行地址转换,将页号送入高速缓存寄存器,并将此页号与快表中的所有页号进行比较。
    2. 若找到匹配的页号,说明所要访问的页表项在快表中,则直接从中取出该页对应的页框号,与页内偏移量拼接形成物理地址。这样,存取数据仅一次访存便可实现。
    3. 若未找到匹配的页号,则需要访问主存中的页表,读出页表项后,应同时将其存入快表,以便后面可能的再次访问。若快表已满,则须按特定的算法淘汰一个旧页表项。

    注意:有些处理机设计为快表和慢表同时查找,若在快表中查找成功则终止慢表的查找。

    一般快表的命中率可达90%以上,这样分页带来的速度损失就可降低至10%以下。快表的有效性基于著名的局部性原理,后面讲解虚拟内存时将会具体讨论它。

     

    4. 两级页表

    由于引入了分页管理,进程在执行时不需要将所有页调入内存页框,而只需将保存有映射关系的页表调入内存。但是,我们仍然需要考虑页表的大小。以.32位逻辑地址空间、页面大小 4KB、页表项大小 4B 为例,若要实现进程对全部逻辑地址空间的映射,则每个进程需要 220 即约100万个页表项:也就是说,每个进程仅页表这一项就需要 4MB 主存空间,而且还要求是连续的,显然这是不切实际的。即便不考虑对全部逻辑地址空间进行映射的情况,一个逻辑地址空间稍大的进程,其页表大小也可能是过大的。以一个40MB的进程为例,页表项共40KB(40MB/4KB×4B),若将所有页表项内容保存在内存中,则需要10个内存页框来保存整个页表。整个进程大小约为1万个页面,而实际执行时只需要几十个页面进入内存页框就可运行,但若要求10个页面大小的页表必须全部进入内存,则相对实际执行时的几十个进程页面的大小来说,肯定降低了内存利用率;从另一方面来说,这10页的页表项也并不需要同时保存在内存中,因为在大多数情况下,映射所需要的页表项都在页表的同一个页面中。

    为了压缩页表,我们进一步延伸页表映射的思想,就可得到二级分页,即使用层次结构的页表:将页表的10页空间也进行地址映射,建立上一级页表,用于存储页表的映射关系。这里对页表的10个页面进行映射只需要10个页表项,所以上一级页表只需要1页就已足够(可以存储210=1024个页表项)。在进程执行时,只需要将这一页的上一级页表调入内存即可,进程的页表和进程本身的页面可在后面的执行中再调入内存。根据上面提到的条件(32位逻辑地址空间、页面大小4KB、页表项大小4B,以字节为编址单位),我们来构造一个适合的页表结构。页面大小为 4KB、页内偏移地址为 log24K=12 位,页号部分为 20 位,若不采用分级页表,则仅页表就要占用22×4B/4KB=1024页,这大大超过了许多进程自身需要的页面;对于内存来说是非常浪费资源的,而且查询页表工作也会变得十分不便、试想若把这些页表放在连续的空间内,查询对应页的物理页号时可以通过页表首页地址+页号x4B的形式得到,而这种方法查询起来虽然相对方便,但连续的1024页对于内存的要求实在太高,并且上面也说到了其中大多数页面都是不会用到的,所以这种方法并不具有可行性。若不把这些页表放在连续的空间里,则需要一张索引表来告诉我们第几张页表该上哪里去找,这能解决页表的查询问题,且不用把所有的页表都调入内存,只在需要它时才调入(下节介绍的虚拟存储器思想),因此能解决占用内存空间过大的问题。读也就是二级页表。为查询方便,顶级页表最多只能有1个页面(一定要记住这个规定),因此顶级页表总共可以容纳4KB/4B=1K个页表项,它占用的地址位数为log21K=10位,而之前已经计算出页内偏移地址占用了12位,因此一个32位的逻辑地址空间就剩下了10位,正好使得二级页表的大小在一页之内,这样就得到了逻辑地址空间的格式,如图3.11所示。

    11

    二级页表实际上是在原有页表结构上再加上一层页表,示意结构如图3.12所示。

    建立多级页表的目的在于建立索引,以便不用浪费主存空间去存储无用的页表项,也不用盲目地顺序式查找页表项。

    12

    0x04 基本分段存储管理

    分页管理方式是从计算机的角度考虑设计的,目的是提高内存的利用率,提升计算机的性能。分页通过硬件机制实现,对用户完全透明。分段管理方式的提出则考虑了用户和程序员,以满足方便编程、信息保护和共享、动态增长及动态链接等多方面的需要。

    1. 分段

    段式管理方式按照用户进程中的自然段划分逻辑空间。例如,用户进程由主程序段、两个子程序段、栈段和数据段组成,于是可以把这个用户进程划分为5段,每段从0开始编址,并分配一段连续的地址空间(段内要求连续,段间不要求连续,因此整个作业的地址空间是二维的),其逻辑地址由段号S与段内偏移量W两部分组成。

    13

    在页式系统中,逻辑地址的页号和页内偏移量对用户是透明的,但在段式系统中,段号和段内偏移量必须由用户显式提供,在高级程序设计语言中,这个工作由编译程序完成。

    2. 段表

    每个进程都有一张逻辑空间与内存空间映射的段表,其中每个段表项对应进程的一段,段表项记录该段在内存中的始址和长度。段表的内容如图3.14所示。

    14

     

    配置段表后,执行中的进程可通过查找段表,找到每段所对应的内存区。可见,段表用于实现从逻辑段到物理内存段的映射,如图 3.15 所示

    15

    3. 地址变换机构

    分段系统的地址变换过程如图 3.16 所示。为了实现进程从逻辑地址到物理地址的变换功能,在系统中设置了段表寄存器,用于存放段表始址 F 和段表长度 M。从逻辑地址 A 到物理地址 E 之间的地址变换过程如下:

    16

    1. 从逻辑地址 A 中取出前几位为段号 S,后几位为段内偏移量 W。注意,在地址变换的题目中,要注意逻辑地址是用二进制数还是用十进制数给出的。
    2. 比较段号 S 和段表长度 M,若 SM,则产生越界中断,否则继续执行。
    3. 段表中段号 S 对应的段表项地址 = 段表始址 F + 段号 S x 段表项长度,取出该段表项的前几位得到段长 C。若段内偏移量 >= C,则产生越界中断,否则继续执行。从这句话我们可以看出,段表项实际上只有两部分,前几位是段长,后几位是始址。
    4. 取出段表项中该段的始址 b,计算 E = b + W,用得到的物理地址 E 去访问外存

    4. 段的共享与保护

    在分段系统中,段的共享是通过两个作业的段表中相应表项指向被共享的段的同一个物理副本来实现的。当一个作业正从共享段中读取数据时,必须防止另一个作业修改此共享段中的数据。不能修改的代码称为纯代码或可重入代码(它不属于临界资源),这样的代码和不能修改的数据可以共享,而可修改的代码和数据不能共享。

    与分页管理类似,分段管理的保护方法主要有两种:一种是存取控制保护,另一种是地址越界保护。地址越界保护将段表寄存器中的段表长度与逻辑地址中的段号比较,若段号大于段表长度,则产生越界中断;再将段表项中的段长和逻辑地址中的段内偏移进行比较,若段内偏移大于段长,也会产生越界中断。分页管理只需要判断页号是否越界,页内偏移是不可能越界的。

    与页式管理不同,段式管理不能通过给出一个整数便确定对应的物理地址,因为每段的长度是不固定的,无法通过整数除法得出段号,无法通过求余得出段内偏移,所以段号和段内偏移一定要显式给出(段号,段内偏移),因此分段管理的地址空间是二维的。

    0x05 段页式管理

    分页存储管理能有效地提高内存利用率,而分段存储管理能反映程序的逻辑结构并有利于段的共享和保护。将这两种存储管理方法结合起来,便形成了段页式存储管理方式。

    在段页式系统中,作业的地址空间首先被分成若干逻辑段,每段都有自己的段号,然后将每段分成若干大小固定的页。对内存空间的管理仍然和分页存储管理一样,将其分成若干和页面大小相同的存储块,对内存的分配以存储块为单位,如图3.17所示。

    17

    在段页式系统中,作业的逻辑地址分为三部分:段号、页号和页内偏移量,如图3.18所示。

    18

    为了实现地址变换,系统为每个进程建立一张段表,每个分段有一张页表。段表表项中至少包括段号、页表长度和页表始址,页表表项中至少包括页号和块号。此外,系统中还应有一个段表寄存器,指出作业的段表始址和段表长度(段表寄存器和页表寄存器的作用都有两个,一是在段表或页表中寻址,二是判断是否越界)。

    注意:在一个进程中,段表只有一个,而页表可能有多个。

    在进行地址变换时,首先通过段表查到页表始址,然后通过页表找到页帧号,最后形成物理地址。如图3.19所示,进行一次访问实际需要三次访问主存,这里同样可以使用快表来加快查找速度,其关键字由段号、页号组成,值是对应的页帧号和保护码。

    19

    结合上面对段式和页式管理地址空间的分析,得出结论:段页式管理的地址空间是二维的。

    段表内保存页表的始址

    0x06 错题记录

    1. 选择题

    1. 存储管理方案中,()可采用覆盖技术。 A. 单一连续存储管理 B. 可变分区存储管理 C. 段式存储管理 D. 段页式存储管理 我的答案:? 参考答案:A

      覆盖技术是早期在单一连续存储管理中使用的扩大存储容量的一种技术,它同样可用于固定分区分配的存储管理。

    2. 动态重定位是在作业的()中进行的。 A. 编译过程 B. 装入过程 C. 链接过程 D. 执行过程 我的答案:B 参考答案:D

      静态装入是指在编程阶段就把物理地址计算好。 可重定位是指在装入时把逻辑地址转换成物理地址,但装入后不能改变 动态重定位是指在执行时再决定装入的地址并装入,装入后有可能会换出,所以同一个模块在内存中的物理地址是可能改变的。 动态重定位是指在作业运行过程中执行到一条访存指令时,再把逻辑地址转换为主存中的物理地址,实际中是通过硬件地址转换机制实现的。

    3. 下面的存储管理方案中,()方式可以采用静态重定位。 A. 固定分区 B. 可变分区 C. 页式 D. 段式 我的答案:? 参考答案:A

      固定分区方式中,作业装入后位置不再改变,可以采用静态重定位。其余三种管理方案均可能在运行过程中改变程序位置,静态重定位不能满足其要求。

    4. 多进程在主存中彼此互不干扰的环境下运行,操作系统是通过()来实现的。 A. 内存分配 B. 内存保护 C. 内存扩充 D. 地址映射 我的答案:B 与 D 之间不确定 参考答案:B

      多进程的执行通过内存保护实现互不干扰,如页式管理中有页地址越界保护,段式管理中有段地址越界保护。

    5. 分区管理中采用最佳适应分配算法时,把空闲区按()次序登记在空闲区表中。 A. 长度递增 B. 长度递减 C. 地址递增 D. 地址递减 我的答案:C 参考答案:A

      最佳适应算法要求从剩余的空闲分区中选出最小且满足存储要求的分区,空闲区应按长度递增登记在空闲区表

    6. 采用分页或分段管理后,提供给用户的物理地址空间()。 A. 分页支持更大的物理地址空间 B. 分段支持更大的物理地址空间 C. 不能确定 D. 一样大 我的答案:A 参考答案:C

      页表和段表同样存储在内存中,系统提供给用户的物理地址空间为总空间大小减去页表或段表的长度。由于页表和段表的长度不能确定,所以提供给用户的物理地址空间大小也不能确定。😅

    7. 对重定位存储管理方式,应( )。 A. 在整个系统中设置一个重定位寄存器 B. 为每道程序设置一个重定位寄存器 C. 为每道程序设置两个重定位寄存器 D. 为每道程序和数据都设置一个重定位寄存器 我的答案:D 参考答案:A

      为使地址转换不影响到指令的执行速度,必须有硬件地址变换结构的支持,即需在系统中增设一个重定位寄存器,用它来存放程序(数据)在内存中的始址。在执行程序或访问数据时,真正访问的内存地址由相对地址与重定位寄存器中的地址相加而成,这时将始址存入重定位寄存器,之后的地址访问即可通过硬件变换实现。因为系统处理器在同一时刻只能执行一条指令或访问数据,所以为每道程序(数据)设置一个寄存器没有必要(同时也不现实,因为寄存器是很昂贵的硬件,而且程序的道数是无法预估的),而只需在切换程序执行时重置寄存器内容。

    8. 采用段式存储管理时,一个程序如何分段是在( )时决定的。 A. 分配主存 B. 用户编程 C. 装作业 D. 程序执行 我的答案:C 参考答案:B

      分段是指在用户编程时,将程序按照逻辑划分为几个逻辑段

    9. 对外存对换区的管理应以( )为主要目标。 A. 提高系统吞吐量 B. 提高存储空间的利用率 C. 降低存储费用 D. 提高换入、换出速度 我的答案:B 参考答案:D

      内存管理是为了提高内存的利用率,引入覆盖和交换技术,即在较小的内存空间中采用重复使用的方法来节省存储空间,但它付出的代价是需要消耗更多的处理器时间,因此实际上是一种以时间换空间的技术。为此,从节省处理器时间上来讲,换入、换出速度越快,付出的时间代价就越小,反之就越大,当时间代价大到一定程度时,覆盖和交换技术就没有了意义。

    10. 在页式存储管理中选择页面的大小,需要考虑下列( )因素。 I.页面大的好处是页表比较少 II.页面小的好处是可以减少由内碎片引起的内存浪费 III.影响磁盘访问时间的主要因素通常不是页面大小,所以使用时优先考虑较大的页面 A. I 和 III B. II 和 III C. I 和 II D. I、II 和 III 我的答案:D 参考答案:C

      页面大,用于管理页面的页表就少,但是页内碎片会比较大; 页面小,用于管理页面的页表就大,但是页内碎片小。 通过适当的计算可以获得较佳的页面大小和较小的系统开销。

      😅不是哥们你这解析也不到位啊

    11. 引入段式存储管理方式,主要是为了更好地满足用户的一系列要求。下面选项中不属于这一系列要求的是()。 A. 方便操作 B. 方便编程 C. 共享和保护 D. 动态链接和增长 我的答案:D 参考答案:A

      引入段式存储管理方式,主要是为了满足用户的下列要求:方便编程、分段共享,分段保护、动态链接和动态增长

      😅那这个方便操作是什么鬼,排除法做题是吧

    12. 把作业空间中使用的逻辑地址变为内存中的物理地址称为()。 A. 加载 B. 重定位 C. 物理化 D. 逻辑化 我的答案:C 正确答案:B

      在一般情况下,一个作业在装入时分配到的内存空间和它的地址空间是不一致的,因此,作业在CPU上运行时,其所要访问的指令、数据的物理地址和逻辑地址是不同的。显然,若在作业装入或执行时,不对有关的地址部分加以相应的修改,则会导致错误的结果。这种将作业的逻辑地址变为物理地址的过程称为地址重定位。

      是了,我特意把题干中“使用的”这三个字给标粗了。

    13. ()存储管理方式提供一维地址结构。 A. 分段 B. 分页 C. 分段和段页式 D. 以上答案都不正确 我的答案:? 正确答案:B

      分页存储管理中,作业地址空间是一维的,即单一的线性地址空间,程序员只需要一个记忆符来表示地址。 在分段存储分配管理中,段之间是独立的,而且段长不定长,而页长是固定的,因此作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。 简言之,确定一个地址需要几个参数,作业地址空间就是几维的

      这道题不会做纯是因为不知道他这个“维”指的是什么。

    14. 下列关于页式存储的论述中,正确的是()。 I.在页式存储管理中,若关闭TLB,则每当访问一条指令或存取一个操作数时都要访问 2次内存 II.页式存储管理不会产生内部碎片 III.页式存储管理中的页面是为用户所感知的 IV.页式存储方式可以采用静态重定位 A. I、II、IV B. I、IV C. 仅 I D. 全都正确 我的答案:B 正确答案:C

      I 正确:关闭TLB后,每当访问一条指令或存取一个操作数时都要先访问页表(内存中),得而无外部碎片。 II 错误:记住,凡是分区固定的都会产生内部碎片,而无外部碎片 III错误:页式存储管理对于用户是透明的。 IV 错误:静态重定位是在程序运行之前由装配程序完成的,必须分配其要求的全部连续内存空间。而页式存储管理方案是将程序离散地分成若干页(块),从而可以将程序装入不连续的内存空间,显然静态重定位不能满足其要求。

    15. 在虚拟内存管理中,地址变换机构将逻辑地址变换为物理地址,形成该逻辑地址的阶段是() A. 编辑 B. 编译 C. 链接 D. 装载 我的答案:D 正确答案:C

      编译后的程序需要经过链接才能装载,而链接后形成的目标程序中的地址也就是逻辑地址。以C语言为例:C程序经过预处理→编译→汇编→链接产生了可执行文件,其中链接的前一步是产生可重定位的二进制目标文件。C语言采用源文件独立编译的方法,如程序 main.c, file1.c, file2.c, file1.h, file2.h 在链接的前一步生成了 main.o, file1.o, file2.o,这些目标模块的逻辑地址都从0开始,但只是相对于该模块的逻辑地址。链接器将这三个文件、libc 和其库文件链接成一个可执行文件,从而形成整个程序的完整逻辑地址空间。

      例如,file1.o 的逻辑地址为 0~1023,main.o 的逻辑地址为0~1023,假设链接时将 file1.o 链接在 main.o 之后,则链接之后 file1.o 对应的逻辑地址应为1024~2047。

     

    二、虚拟内存管理

    0x00 虚拟内存的基本概念

    1. 传统存储管理方式的特征

    第一节讨论的各种内存管理策略都是为了同时将多个进程保存在内存中,以便允许进行多道程序设计。它们都具有以下两个共同的特征:

    1. 一次性。作业必须一次性全部装入内存后,才能开始运行。这会导致两种情况: ①当作业很大而不能全部被装入内存时,将使该作业无法运行; ②当大量作业要求运行时,由于内存不足以容纳所有作业,只能使少数作业先运行,导致多道程序度的下降。
    2. 驻留性。作业被装入内存后,就一直驻留在内存中,其任何部分都不会被换出;直至作业运行结束。运行中的进程会因等待IO而被阻塞,可能处于长期等待状态。

    由以上分析可知,许多在程序运行中不用活暂时不用的程序(数据)占用了大量的内存空间,而一些需要运行的作业又无法装入运行,显然浪费了宝贵的内存资源。

    2. 局部性原理

    要真正理解虚拟内存技术的思想,首先须了解著名的局部性原理。从广义上讲,快表、页高速缓存及虚拟内存技术都属于高速缓存技术,这个技术所依赖的原理就是局部性原理。局部性原理既适用于程序结构,又适用于数据结构。

    局部性原理表现在以下两个方面:

    1. 时间局部性。程序中的某条指令一旦执行,不久后该指令可能再次执行:某数据被访问过,不久后该数据可能再次被访问。产生的原因是程序中存在着大量的循环操作。
    2. 空间局部性。一旦程序访问了某个存储单元,在不久后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式簇聚存储的。

    时间局部性通过将近来使用的指令和数据保存到高速缓存中,并使用高速缓存的层次结构实现。空间局部性通常使用较大的高速缓存,并将预取机制集成到高速缓存控制逻辑中实现。虚拟内存技术实际上建立了“内存-外存”的两级存储器结构,利用局部性原理实现高速缓存。

    3. 虚拟存储器的定义和特征

    基于局部性原理,在程序装入时,仅须将程序当前要运行的少数页面或段先装入内存,而将其余部分暂留在外存,便可启动程序执行。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的信息。这样,系统好像为用户提供了一个比实际内存容量大得多的存储器,称为虚拟存储器

    之所以将其称为虚拟存储器,是因为这种存储器实际上并不存在,.只是由于系统提供了部分装入、请求调入和置换功能后(对用户透明),给用户的感觉是好像存在一个比实际物理内存大得多的存储器。但容量大只是一种错觉,是虚的。虚拟存储器有以下三个主要特征:

    1. 多次性。是指无须在作业运行时一次性地全部装入内存,而允许被分成多次调入内存运行,即只需将当前要运行的那部分程序和数据装入内存即可开始运行。以后每当要运行到尚未调入的那部分程序时,再将它调入。多次性是虚拟存储器最重要的特征。
    2. 对换性。是指无须在作业运行时一直常驻内存,在进程运行期间,允许将那些暂不使用的程序和数据从内存调至外存的对换区(换出),待以后需要时再将它们从外存调至内存(换进)。正是由于对换性,才使得虚拟存储器得以正常运行。
    3. 虚拟性。是指从逻辑上扩充内存的容量,使用户所看到的内存容量远大于实际的内存容量。这是虚拟存储器所表现出的最重要特征,也是实现虚拟存储器的最重要目标。

    4. 虚拟内存技术的实现

    虚拟内存技术允许将一个作业分多次调入内存。采用连续分配方式时,会使相当一部分内存空间都处于暂时或”永久“的空闲状态,造成内存资源的严重浪费,而且也无法从逻辑上扩大存容量。因此,虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。虚拟内存的实现有以下三种方式:

    不管哪种方式,都需要有一定的硬件支持。一般需要的支持有以下几个方面:

     

    0x01 请求分页管理方式

    请求分页系统建立在基本分页系统基础之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。

    在请求分页系统中,只要求将当前需要的一部分页面装入内存,便可以启动作业运行。在作业执行过程中,当所要访问的页面不在内存中时,再通过调页功能将其调入,同时还可通过置换功能将暂时不用的页面换出到外存上,以便腾出内存空间。

    为了实现请求分页,系统必须提供一定的硬件支持。除了需要一定容量的内存及外存的计算机系统,还需要有页表机制、缺页中断机构和地址变换机构。

    1. 页表机制

    请求分页系统的页表机制不同于基本分页系统,请求分页系统在一个作业运行之前不要求全部一次性调入内存,因此在作业的运行过程中,必然会出现要访问的页面不在内存中的情况,如何发现和处理这种情况是请求分页系统必须解决的两个基本问题。为此,在请求页表项中增加了4个字段,如图3.20所示。

    20

    增加的4个字段说明如下:

    2. 缺页中断机构

    在请求分页系统中,每当所要访问的页面不在内存中时,便产生一个缺页中断,请求操作系统将所缺的页调入内存。此时应将缺页的进程阻塞(调页完成唤醒),若内存中有空闲块,则分配一个块,将要调入的页装入该块,并修改页表中的相应页表项,若此时内存中没有空闲块,则要淘汰某页(若被淘汰页在内存期间被修改过,则要将其写回外存)。

    缺页中断作为中断,同样要经历诸如保护 CPU 环境、分析中断原因、转入缺页中断处理程序、恢复CPU环境等几个步骤。但与一般的中断相比,它有以下两个明显的区别:

    3. 地址变换机构

    请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,为实现虚拟内存,又增加了某些功能而形成的,如产生和处理缺页中断,及从内存中换出一页的功能等待。

    如图3.21所示,在进行地址变换时,先检索快表:

    21

    0x02 页框分配

    1. 驻留集大小

    对于分页式的虚拟内存,在进程准备执行时,不需要也不可能把一个进程的所有页都读入主存。因此,操作系统必须决定读取多少页,即决定给特定的进程分配几个页框。给一个进程分配的物理页框的集合就是这个进程的驻留集。需要考虑以下几点:

    1. 分配给一个进程的页框越少,驻留在主存中的进程就越多,从而可提高CPU的利用率。
    2. 若一个进程在主存中的页面过少,则尽管有局部性原理,缺页率仍相对较高。
    3. 若分配的页框过多,则由于局部性原理,对该进程的缺页率没有太明显的影响。

    2. 内存分配策略

    在请求分页系统中,可采取两种内存分配策略,即固定和可变分配策略。在进行置换时,也可采取两种策略,即全局置换和局部置换。于是可组合出下面三种适用的策略。

    (1) 固定分配局部置换

    为每个进程分配一定数目的物理块,在进程运行期间都不改变。所谓局部置换,是指如果进程在运行中发生缺页,则只能从分配给该进程在内存的页面中选出一页换出,然后再调入一页,以保证分配给该进程的内存空间不变。实现这种策略时,难以确定应为每个进程分配的物理块数目:太少会频繁出现缺页中断,太多又会降低CPU和其他资源的利用率。

    (2) 可变分配全局置换

    先为每个进程分配一定数目的物理块,在进程运行期间可根据情况适当地增加或减少。所谓全局置换,是指如果进程在运行中发生缺页,系统从空闲物理块队列中取出一块分配给该进程,并将所缺页调入。这种方法比固定分配局部置换更加灵活,可以动态增加进程的物理块,但也存在弊端,如它会盲目地给进程增加物理块,从而导致系统多道程序的并发能力下降。

    (3) 可变分配局部置换

    为每个进程分配一定数目的物理块,当某进程发生缺页时,只允许从该进程在内存的页面中选出一页换出,因此不会影响其他进程的运行。若进程在运行中频繁地发生缺页中断,则系统再为该进程分配若干物理块,直至该进程的缺页率趋于适当程度;反之,若进程在运行中的缺页率特别低,则可适当减少分配给该进程的物理块,但不能引起其缺页率的明显增加。这种方法在保证进程不会过多地调页的同时,也保持了系统的多道程序并发能力。当然它需要更复杂的实现,也需要更大的开销,但对比频繁地换入/换出所浪费的计算机资源,这种牺牲是值得的。

    页面分配策略在 2015年的统考选择题中出现过,考查的是这三种策略的名称。往年很多读者看到这里时,由于认为不是重点,复习时便一带而过,最后在考试中失分。在这种基础题上失分是十分可惜的。再次提醒读者,考研成功的秘诀在于“反复多次”和“全面”。

    3. 物理块调入算法

    采用固定分配策略时,将系统中的空闲物理块分配给各个进程,可采用下述几种算法。

    1. 平均分配算法,将系统中所有可供分配的物理块平均分配给各个进程。
    2. 按比例分配算法,根据进程的大小按比例分配物理块。
    3. 优先权分配算法,为重要和紧迫的进程分配较多的物理块。

    通常采取的方法是把所有可分配的物理块分成两部分: 一部分按比例分配给各个进程 一部分则根据优先权分配

    4. 调入页面的时机

    为确定系统将进程运行时所缺的页面调入内存的实际,可采取以下两种调页策略:

    1. 预调页策略。根据局部性原理,一次调入若干相邻的页会比一次调入一页更高效。但若调入的一批页面中的大多数都未被访问,则又是低效的。因此,需要采用以预测为基础的预调页策略,将那些预计在不久之后便会被访问的页面预先调入内存。但目前预调页的成功率仅约50%。因此这种策略主要用于进程的首次调入,由程序员指出应先调入哪些页。
    2. 请求调页策略。进程在运行中需要访问的页面不在内存,便提出请求,由系统将其所需页面调入内存。由这种策略调入的页一定会被访问,且这种策略比较易于实现,因此目前的虚拟存储器大多采用此策略。其缺点是每次仅调入一页,增加了磁盘 I/O 开销。

    预调入实际上就是运行前的调入,请求调页实际上就是运行期间调入。

    5. 从何处调入页面

    请求分页系统的外存分为两部分:用于存放文件的文件区和用于存放对换页面的对换区。对换区采用连续分配方式,而文件区采用离散分配方式,因此对换区的磁盘 I/O 速度比文件区的更快。这样,当发生缺页请求时,系统从何处将缺页调入内存就分为三种情况:

    1. 系统拥有足够的对换区空间。可以全部从对换区调入所需页面,以提高调页速度。为此,在进程运行前,需将与该进程有关的文件从文件区复制到对换区。
    2. 系统缺少足够的对换区空间。凡是不会被修改的文件都直接从文件区调入;而当换出这些页面时,由于它们未被修改而不必再将它们换出。但对于那些可能被修改的部分,在将它们换出时须调到对换区,以后需要时再从对换区调入(因为读比写的速度快)
    3. UNIX方式。与进程有关的文件都放在文件区,因此未运行过的页面都应从文件区调入。曾经运行过但又被换出的页面,由于是放在对换区,因此在下次调入时应从对换区调入。进程请求的共享页面若被其他进程调入内存,则无须再从对换区调入。

    6. 如何调入页面

    当进程所访问的页面不在内存中时(存在位为0),便向CPU发出缺页中断,中断响应后便转入缺页中断处理程序。该程序通过查找页表得到该页的物理块,此时如果内存未满,则启动磁盘 I/O,将所缺页调入内存,并修改页表。如果内存已满,则先按某种置换算法从内存中选出一页准备换出;如果该页未被修改过(修改位为0),则无须将该页写回磁盘;但是,如果该页已被置其存在位为1。调入完成后,进程就可利用修改后的页表形成所要访问数据的内存地址。

    0x03 页面置换算法

    进程运行时,若其访问的页面不在内存中而需将其调入,但内存已无空闲空间时,就需要从内存中调出一页程序或数据,送入磁盘的对换区。

    选择调出页面的算法就称为页面置换算法。好的页面置换算法应有较低的页面更换频率,也就是说,应将以后不会再访问或以后较长时间内不会再访问的页面先调出。

    常见的置换算法有以下4种。

    1. 最佳(OPT)置换算法

    最佳置换算法选择的被淘汰页面是以后永不使用的页面,或是在最长时间内不再被访问的页面,以便保证获得最低的缺页率。然而,由于人们目前无法预知进程在内存下的若干页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。但可利用该算法去评价其他算法。

    假定系统为某进程分配了三个物理块,并考虑有页面号引用串:

    7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1

    进程运行时,先将7,0,1三个页面依次装入内存。当进程要访问页面2时,产生缺页中断,根据最佳置换算法,选择将第18次访问才需调入的页面7淘汰。然后,访问页面0时,因为它已在内存中,所以不必产生缺页中断。访问页面3时,又会根据最佳置换算法将页面1淘汰···以此类推;如图3.22所示,从图中可以看出采用最佳置换算法时的情况。

    22

    2. 先进先出(FIFO)页面置换算法

    优先淘汰最早进入内存的页面,即淘汰在内存中驻留时间最久的页面。该算法实现简单,只需把已调入内存的页面根据先后次序链接成队列,设置一个指针总是指向最老的页面。但该算法与进程实际运行时的规律不适应,因为在进程中,有的页面经常被访问。

    这里仍用上面的例子采用 FIFO 算法进行页面置换。当进程访问页面 2 时,把最早进入内存的页面 7 换出。然后访问页面 3 时,把 2, 0, 1 中最先进入内存的页面 0 换出。由图3.23可以看出,利用FIFO算法时进行了12次页面置换,比最佳置换算法正好多一倍。

    FIFO 算法还会产生所分配的物理块数增大而页故障数不减反增的异常现象,称为 Belady 异常只有 FIFO 算法可能出现 Belady 异常,LRU 和 OPT 算法永远不会出现Belady异常

    23

    如图 3.24 所示,页面访问顺序为 3, 2, 1, 0, 3, 2, 4, 3, 2, 1, 0, 4 若采用 FIFO 置换算法,当分配的物理块为 3 个时,缺页次数为 9 次;当分配的物理块为 4 个时,缺页次数为10 次。分配给进程的物理块增多,但缺页次数不减反增。

    24

    3. 最近最久未使用(LRU)置换算法

    选择最近最长时间未访问过的页面予以淘汰,它认为过去一段时间内未访问过的页面,在最近的将来可能也不会被访问。该算法为每个页面设置一个访问字段,用来记录页面自上次被访问以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。

    再对上面的例子采用 LRU 算法进行页面置换,如图 3.25 所示。进程第一次对页面 2 访问时,将最近最久未被访问的页面 7 置换出去。然后在访问页面 3 时,将最近最久未使用的页面 1 换出。

    25

    在图 3.25 中,前 5 次置换的情况与最佳置换算法相同,但两种算法并无必然联系。实际上,LRU 算法根据各页以前的使用情况来判断,是“向前看”的,而最佳置换算法则根据各页以后的使用情况来判断,是“向后看”的。而页面过去和未来的走向之间并无必然联系。

    LRU算法的性能较好,但需要寄存器和栈的硬件支持。LRU 是堆栈类的算法。理论上可以证明,堆栈类算法不可能出现 Belady 异常。FIFO 算法基于队列实现,不是堆栈类算法。

    4. 时钟(CLOCK)置换算法

    LRU算法的性能接近 OPT 算法,但实现起来的开销大。因此,操作系统的设计者尝试了很多算法,试图用比较小的开销接近 LRU 算法的性能,这类算法都是CLOCK 算法的变体。

    (1) 简单的 CLOCK 置换算法

    为每帧设置一位访问位,当某页首次被装入被访问时,其访问位被置为1。 对于替换算法,将内存中的所有页面视为一个循环队列,并有一个替换指针与之相关联,当某一页被替换时,该指针被设置指向被替换页面的下一页 在选择一页淘汰时,只需检查页的访问位。若为 0,就选择该页换出;若为1,则将它置为0,暂不换出,给予该页第二次驻留内存的机会,再依次顺序检查下一个页面。 当检查到队列中的最后一个页面时,若其访问位仍为1,则返回到队首去循环检查。 由于该算法是循环地检查各个页面的使用情况,故称 CLOCK 算法。但是,因为该算法只有一位访问位,而置换时将未使用过的页面换出,故又称最近未用(NRU)算法。

    假设页面的访问顺序为 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 3, 2 配4个页帧,每个页对应的结构为(页面号,访问位),置换过程如图 3.26 所示。

    26

    首次访问 7, 0, 1, 2 时,产生缺页中断,依次调入主存,访问位都置为 1。访问 0 时,已存在,访问位置为 1。访问3时,产生第 5 次缺页中断,替换指针初始指向帧1,此时所有帧的访问位均为1,则替换指针完整地扫描一周,把所有帧的访问位都置为0,然后回到最初的位置(帧1),替换帧1中的页(包括置换页面和置访问位为1),如图3.27(a)所示。访问0时,已存在,访问位置为1。访问4时,产生第6次缺页中断,替换指针指向帧2(上次替换位置的下一帧),帧2的访问位为1,将其修改为0,继续扫描,帧3的访问位为0,替换帧3中的页,如图3.27(b)所示。然后依次访问 2, 3, 0, 3, 2,均已存在,每次访问都将其访问位置为1。访问1时,产生缺页中断,替换指针指向帧4,此时所有帧的访问位均为1,又完整扫描一周并置访问位为0,回到帧4,替换之。访问3时,已存在,访问位置为1。访问2时,产生缺页中断,替换指针指向帧1,帧1的访问位为1,将其修改为0,继续扫描,帧2的访问位为0,替换帧2中的页。

    27

    (2) 改进型CLOCK置换算法

    将一个页面换出时,若该页已被修改过,则要将该页写回磁盘,若该页未被修改过,则不必将它写回磁盘。可见,对于修改过的页面,替换代价更大。在改进型CLOCK算法中,除考虑页面使用情况外,还增加了置换代价一一修改位。在选择页面换出时,优先考虑既未使用过又未修改过的页面。由访问位A和修改位M可以组合成下面四种类型的页面:

    内存中的每页必定都是这四类页面之一。在进行页面置换时,可采用与简单CLOCK算法类似的算法,差别在于该算法要同时检查访问位和修改位。算法执行过程如下:

    1. 从指针的当前位置开始,扫描循环队列,寻找 A = 0 且 M = 0 的1类页面,将遇到的第一个1类页面作为选中的淘汰页。在第一次扫描期间不改变访问位A。
    2. 若第 1 步失败,则进行第二轮扫描,寻找 A = 0 且 M = 1 的 2 类页面。将遇到的第一个 2 类页面作为淘汰页。在第二轮扫描期间,将所有扫描过的页面的访问位都置0。
    3. 若第 2 步也失败,则将指针返回到开始的位置,并将所有帧的访问位复0。重复第 1 步,并且若有必要,重复第 2 步,此时一定能找到被淘汰的页。

    改进型CLOCK 算法优于简单CLOCK 算法的地方在于,可减少磁盘的 I/O 操作次数。但为了找到一个可置换的页,可能要经过几轮扫描,即实现算法本身的开销将有所增加。

    操作系统中的页面置换算法都有一个原则,即尽可能保留访问过的页面,而淘汰未访问的页分为修改过的页面和未修改的页面。因此,若有未使用过的页面,则当然优先将其中未修改过的页面换出。若全部页面都用过,还是优先将其中未修改过的页面换出。

    0x04 抖动和工作集

    1. 抖动

    在页面置换过程中,一种最糟糕的情形是,刚刚换出的页面马上又要换入主存,刚刚换入的页面马上又要换出主存,这种频繁的页面调度行为称为抖动或颠簸

    系统发生抖动的根本原因是,系统中同时运行的进程太多,由此分配给每个进程的物理块太少,不能满足进程正常运行的基本要求,致使每个进程在运行时频繁地出现缺页,必须请求系统将所缺页面调入内存。这会使得在系统中排队等待页面调入/调出的进程数目增加。显然,对磁盘能再去做任何有效的工作,进而导致发生处理机的利用率急剧下降并趋于零的情况。

    抖动是进程运行时出现的严重问题,必须采取相应的措施解决它。由于抖动的发生与系统为进程分配物理块的多少有关,于是又提出了关于进程工作集的概念。

    2. 工作集

    工作集是指在某段时间间隔内,进程要访问的页面集合。基于局部性原理,可以用最近访问过的页面来确定工作集。一般来说,工作集W可由时间t和工作集窗口大小 Δ 来确定。例如,某进程对页面的访问次序如下:

    28

    假设系统为该进程设定的工作集窗口大小 Δ 为 5,则在 t1 时刻,进程的工作集为 {2,3,5},在 t2 时刻,进程的工作集为 {1,2,3,4}

    实际应用中,工作集窗口会设置得很大,即对于局部性好的程序,工作集大小一般会比工作集窗口 Δ 小很多。工作集反映了进程在接下来的一段时间内很有可能会频繁访问的页面集合,因此,若分配给进程的物理块小于工作集大小,则该进程就很有可能频繁缺页,所以为了防止这种抖动现象,一般来说分配给进程的物理块数(即驻留集大小)要大于工作集大小。

    工作集模型的原理是,让操作系统跟踪每个进程的工作集,并为进程分配大于其工作集的物理块。落在工作集内的页面需要调入驻留集中,而落在工作集外的页面可从驻留集中换出。若还有空闲物理块,则可再调一个进程到内存。若所有进程的工作集之和超过了可用物理块总数,则操作系统会暂停一个进程,将其页面调出并将物理块分配给其他进程,防止出现抖动现象。

     

    0x05 内存映射文件

    内存映射文件(Memory-Mapped Files)与虚拟内存有些相似,将磁盘文件的全部或部分内容与进程虚拟地址空间的某个区域建立映射关系,便可以直接访问被映射的文件,而不必执行文件 I/O 操作,也无须对文件内容进行缓存处理。这种特性非常适合用来管理大尺寸文件。

    使用内存映射文件所进行的任何实际交互都是在内存中进行的,并且是以标准的内存地址形式来访问的。磁盘的周期性分页是由操作系统在后台隐蔽实现的,对应用程序而言是完全透明的。系统内存中的所有页面都由虚拟存储器负责管理,虚拟存储器以统一的方式处理所有磁盘I/O。当进程退出或显式地解除文件映射时,所有被改动的页面会被写回磁盘文件。

    多个进程允许并发地内存映射同一文件,以便允许数据共享。实际上,很多时候,共享内存是通过内存映射来实现的。进程可以通过共享内存来通信,而共享内存是通过映射相同文件到通信进程的虚拟地址空间实现的。内存映射文件充当通信进程之间的共享内存区域,如图3.28所示。一个进程在共享内存上完成了写操作,此刻当另一个进程在映射到这个文件的虚拟地址空间上执行读操作时,就能立刻看到上一个进程写操作的结果。

    29

    0x06 虚拟存储器性能影响因素

    “抖动和工作集”一节原本是2017年统考大纲中已删除的考点,但是2022年的统考大纲中新增了考点“虚拟存储器性能影响因素及改进方式”。缺页率(缺页率高即为抖动)是影响虚拟存储器性能的主要因素,且缺页率又受到页面大小、分配给进程的物理块数(取决于工作集)页面置换算法以及程序的编制方法的影响。因此,该考点也与本节的内容相关。

    根据局部性原理,页面较大则缺页率较低,页面较小则缺页率较高。页面较小时,一方面减少了内存碎片,有利于提高内存利用率;另一方面,也会使每个进程要求较多的页面,导致页表过长,占用大量内存。页面较大时,虽然可以减少页表长度,但会使页内碎片增大。

    分配给进程的物理块数越多,缺页率就越低,但是当物理块超过某个数目时,再为进程增加一个物理块对缺页率的改善是不明显的。可见,此时已没有必要再为它分配更多的物理块,否则也只能是浪费内存空间。只要保证活跃页面在内存中,保持缺页率在一个很低的范围即可。

    好的页面置换算法可使进程在运行过程中具有较低的缺页率。选择LRU、CLOCK等置换算法,将未来有可能访问的页面尽量保留在内存中,从而提高页面的访问速度。

    写回磁盘(见《计算机组成原理考研复习指导》)的频率。换出已修改过的页面时,应当写回磁盘,如果每当一个页面被换出时就将它写回磁盘,那么每换出一个页面就需要启动一次磁盘,效率极低。为此在系统中建立一个已修改换出页面的链表,对每个要被换出的页面(已修改),可以暂不将它们写回磁盘,而将它们挂在该链表上,仅当被换出页面数达到给定值时,才将它们一起写回磁盘,这样就可显著减少磁盘1/O的次数,即减少已修改页面换出的开销。此外,如果有进程在这批数据还未写回磁盘时需要再次访问这些页面,就不需从外存调入,而直接从已修改换出页面链表上获取,这样也可以减少页面从磁盘读入内存的频率,减少页面换进的开销。

    编写程序的局部化程度越高,执行时的缺页率就越低。如果存储采用的是按行存储,访问时就要尽量采用相同的访问方式,:避免按列访问造成缺页率过高的现象。

    0x07 地址翻译

    考虑到统考真题越来越喜欢考查学科综合的趋势,这里结合“计算机组成原理”的.Cache部分,来说明虚实地址的变换过程。对于不参加统考的读者,可视情况跳过本节;对于参加统考却尚未复习计算机组成原理的读者,可在复习之后,再回过头来学习本节内容。

    设某系统满足以下条件:

    写出访问地址为 0x03d4, 0x00f1, 0x0229 的过程。

    因为本系统以字节编址,页面大小为 64B,则页内偏移地址为 log2(64B/1B)= 6位,所以虚拟页号为 14 - 6 = 8 位,物理页号为 12 - 6 = 6 位。因为 TLB 为四路组相联,共有16个条目,则 TLB 共有16 / 4 = 4 组,因此虚拟页号中低 log24=2 位就为组索引,高 6 位就为 TLB 标记。又因为 Cache 行大小为 4B,因此物理地址中低 log24=2 位为块偏移,Cache 共有 16 组,可知接下来 log216=4 位为组索引,剩下高6位作为标记。地址结构如图3.29所示。

    30

    TLB、页表、data Cache 内容如表3.1、表 3.2.及表 3.3所示。

    31

    32

    先把十六进制的虚拟地址 0x03d4, 0x00f1, 0x0229 转化为二进制形式,如表3.4所示。

    33

    得到每个地址的组索引和 TLB标记,接下来就要找出每个地址的页面在不在主存中,若在主存中,则还要找出物理地址。

    对于0x03d4,组索引为 3,TLB 标记为 0x03,查 TLB,第 3 组中正好有标记为 03 的项,有效位为1,可知页面在主存中,对应的物理页号为0d(001101),再拼接页内地址010100,可得物理地址为0x354(001101010100)。

    对于 0x00f1,组索引为3,TLB 标记为0x00,查 TLB,第3 组中没有标记为 00的项,再去找页表,虚拟页号为0x03,页表第3行的有效位为1,可知页面在主存中,物理页号为02(000010),再拼接页内地址110001,可得物理地址为0x0b1(000010110001)。

    对于 0x0229,组索引为0,TLB 标记为0x02,查TLB,第0组中没有标记为02的项,再去找页表,虚拟页号为0x08,页表第8行的有效位为0,页面不在主存中,产生缺页中断。

    找出在主存中的页面的物理地址后,就要通过物理地址访问数据,接下来要找该物理地址的内容在不在Cache中,物理地址结构如表3.5所示。

    34

    对于 0x354,Cache 索引为 5,Cache 标记为 0x0d,对照 Cache 中索引为5的行,标记正好为 0d,有效位为1,可知该块在Cache 中,偏移0,即块0,可得虚拟地址 0x03d4 的内容为 36H。

    对于 0x0b1,Cache 索引为 c,Cache 标记为 0x02,对照 Cache 中索引为c的行,有效位为 0,可知该块不在 Cache 中,要去主存中查找物理页号为 2、偏移为 0x31的内容

    以上例子基本覆盖了从虚拟地址到Cache 查找内容的所有可能出现的情况,读者务必要掌握此节的内容,查找顺序是从 TLB 到页表(TLB 不命中),再到 Cache 和主存,最后到外存。

    0x08 错题记录

    1. 在请求分页存储管理中,若采用 FIFO 页面淘汰算法;则当可供分配的页帧数增加时,缺页中断的次数() A. 减少 B. 增加 C. 无影响 D. 可能增加也可能减少 我的答案:B 参考答案:D

      请求分页存储管理中,若采用FIFO页面淘汰算法,可能会产生当驻留集增大时页故障数不减反增的 Belady 异常。然而,还有另外一种情况。例如,页面序列为1,2,3,1,2,3,当页帧数为2时产生6次缺页中断,当页帧数为3时产生3次缺页中断。所以在请求分页存储管理中,若采用FIFO页面淘汰算法,则当可供分配的页顿数增加时,缺页中断的次数可能增加,也可能减少。

    2. 设主存容量为1MB,外存容量为 400MB,计算机系统的地址寄存器有 32 位,那么虚拟存储器的最大容量是() A. 1MB B. 401 MB C. 1MB + 232MB D. 232B 我的答案:B 参考答案:D

      虚拟存储器的最大容量是由计算机的地址结构决定的,与主存容量和外存容量没有必然的联系,其虚拟地址空间为232B

      😅试图把我激怒

    3. 导致 LRU 算法实现起来耗费高的原因是( )。 A. 需要硬件的特殊支持 B. 需要特殊的中断处理程序 C. 需要在页表中标明特殊的页类型 D. 需要对所有的页进行排序 我的答案:A 参考答案:D

      LRU 算法需要对所有页最近一次被访问的时间进行记录,查找时间最久的进行替换,这涉及排序,对置换算法而言,开销太大。为此需要在页表项中增加 LRU 位,选项A可视为“耗费高”这一结果,选项D才是造成选项A的原因。

    4. 在页面置换策略中,()策略可能引起抖动。 A. FIFO B. LRU C. 没有一种 D. 所有 我的答案:A 参考答案:D

      抖动是进程的页面置换过程中,频繁的页面调度(缺页中断)行为,所有的页面调度策略都不可能完全避免抖动。

    5. 在请求分页存储管理的页表中增加了若干项信息,其中修改位和访问位供()参考。 A. 分配页面 B. 调入页面 C. 置换算法 D. 程序访问 我的答案:B 参考答案:C

      当需要置换页面时,置换算法根据修改位和访问位选择调出内存的页面。

    6. 页式虚拟存储管理的主要特点是()。 A. 不要求将作业装入主存的连续区域 B. 不要求将作业同时全部装入主存的连续区域 C. 不要求进行缺页中断处理 D. 不要求进行页面置换 我的答案:A 参考答案:B

      页式虚拟存储管理的主要特点是,不要求将作业同时全部装入主存的连续区域,一般只装入10%~30%。不要求将作业装入主存连续区域是所有离散式存储管理(包括页式存储管理)的特点:页式虚拟存储管理需要进行缺页中断处理和页面置换。

    7. 提供虚拟存储技术的存储管理方法有()。 A. 动态分区存储管理 B. 页式存储管理 C. 请求段式存储管理 D. 存储覆盖技术 我的答案:B 参考答案:C

      虚拟存储技术是基于页或段从内存的调入/调出实现的,需要有请求机制的支持。

    8. 在虚拟分页存储管理系统中,若进程访问的页面不在主存中,且主存中没有可用的空闲帧时;系统正确的处理顺序为()。 A. 决定淘汰页→页面调出→缺页中断→页面调入 B. 决定淘汰页→页面调入→缺页中断→页面调出 C. 缺页中断→决定淘汰页→页面调出→页面调入 D. 缺页中断→决定淘汰页→页面调入→页面调出 我的答案:A 参考答案:C

      没看清缺页中断😂

    9. 已知系统为32位实地址,采用48位虚拟地址,页面大小为4KB,页表项大小为8B假设系统使用纯页式存储;则要采用()级页表,页内偏移()位。 A. 3, 12 B. 3, 14 C. 4, 12 D. 4, 14 我的答案:A 参考答案:C

      页面大小为 4KB,因此页内偏移为12 位。系统采用 48 位虚拟地址,因此虚页号 48-12 = 36 位。采用多级页表时,最高级页表项不能超出一页大小;每页能容纳的页表项数为4KB/8B=512=29,36/9=4,因此应采用4 级页表,最高级页表项正好占据一页空间,所以本题选择选项C

    四、本章疑难点

    分页管理方式和分段管理方式在很多地方是相似的,比如在内存中都是不连续的、都有地址变换机构来进行地址映射等。但两者也存在许多区别,表3.6列出了两种方式的对比。

     分页分段
    目的分页仅是系统管理上的需要,是为实现离散分配方式,以提高内存的利用率。而不是用户的需要段是信息的逻辑单位,它含有一组意义相对完整的信息。分段的目的是能更好地满足用户的需要
    长度页的大小固定且由系统决定,由系统把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的段的长度不固定,决定于用户所编写的程序,通常由编译程序在编译时根据信息的性质来化粪
    地址空间分页的程序地址空间是一维的,即单一的线性地址空间,程序员利用一个记忆符即可表示一个地址分段的程序地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址
    碎片有内部碎片,无外部碎片有外部碎片,无内部碎片