目录
2.3.4 时钟(CLOCK) 置换算法(最近未用算法, Not RecntyUsed,,NRU)
1 内存管理
1.1 内存管理的原理
1.1.1 内存管理的概念
操作系统对内存的划分和动态分配。
1.1.2 内存管理的意义
- 方便用户使用存储器
- 提高内存利用率
- 可以通过虚拟技术从逻辑上扩充存储器
1.1.3 内存管理的功能
- 内存空间的分配与回收:由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储分配的麻烦,提高编程效率。
- 地址转换:在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可-一致,因此存储管理必须提供地址变换功能,把逻辑地址转换成相应的物理地址。
- 内存空间的扩充:利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存。
- 存储保护:保证各道作业在各自的存储空间内运行,互不干扰。
1.1.4 进程运行的基本原理
1.程序装入和链接
创建进程首先要将程序和数据装入内存。将用户源程序变为可在内存中执行的程序,通常需以下几个步骤,如图所示:
- 编译:由编译程序将用户源代码编译成若干目标模块。
- 链接:由链接程序将编译后形成的一组目标模块及所需的库函数链接在一-起, 形成一个完整的装入模块。
- 装入:由装入程序将装入模块装入内存运行。
2.逻辑地址空间与物理地址空间
编译后,每个目标模块都从0号单元开始编址,这称为该目标模块的相对地址(或逻辑地址)。当链接程序将各个模块链接成一个完整的可执行目标程序时,链接程序顺序依次按各个模块的相对地址构成统一的从0号单元开始编址的逻辑地址空间。用户程序和程序员只需知道逻辑地址,而内存管理的具体机制则是完全透明的,只有系统编程人员才会涉及内存管理的具体机制。不同进程可以有相同的逻辑地址,因为这些相同的逻辑地址可以映射到主存的不同位置。
物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址,进程在运行时执行指令和访问数据,最后都要通过物理地址从主存中存取。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位。
3.内存保护
内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。内存保护可采取两种方法:
- 在CPU中设置一 对上、下限寄存器,存放用户作业在主存中的下限和上限地址,每当CPU要访问一个地址时,分别和两个寄存器的值相比,判断有无越界。
- 采用重定位寄存器(或基址寄存器)和界地址寄存器(又称限长寄存器)来实现这种保护。重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址的最大值。每个逻辑地址值必须小于界地址寄存器;内存管理机构动态地将逻辑地址与界地址寄存器进行比较,若未发生地址越界,则加上重定位寄存器的值后映射成物理地址,再送交内存单元,如图所示。.
当CPU调度程序选择进程执行时,派遺程序会初始化重定位寄存器和界地址寄存器。每个逻辑地址都需要与这两个寄存器进行核对,以保证操作系统和其他用户程序及数据不被该进程的运行影响。
实现内存保护需要重定位寄存器和界地址寄存器,因此要注意两者的区别。重定位寄存器是用来“加”的,逻辑地址加上重定位寄存器中的值就能得到物理地址;界地址寄存器是用来“比”的,通过比较界地址寄存器中的值与逻辑地址的值来判断是否越界。
1.2 覆盖与交换
覆盖与交换技术是在多道程序环境下用来扩充内存的两种方法。
1.2.1 覆盖
早期的计算机系统中,主存容量很小,虽然主存中仅存放一-道用户程序, 但存储空间放不下用户进程的现象也经常发生,这一矛盾可以用覆盖技术来解决。
覆盖的基本思想:
由于程序运行时并非任何时候都要访问程序及数据的各个部分(尤其是大程序),因此可把用户空间分成一一个固定区和若干覆盖区。
将经常活跃的部分放在固定区,其余部分按调用关系分段。
首先将那些即将要访问的段放入覆盖区,其他段放在外存中,在需要调用前,系统再将其调入覆盖区,替换覆盖区中原有的段。
覆盖技术的特点:
打破了必须将一个进程的全部信息装入主存后才能运行的限制,但当同时运行程序的代码量大于主存时仍不能运行,此外,内存中能够更新的地方只有覆盖区的段,不在覆盖区中的段会常驻内存。
1.2.2 交换
交换(对换)的基本思想:
把处于等待状态(或在CPU调度原则下被剥夺运行权利)的程序从内存移到辅存,把内存空间腾出来,这一过程又称换出;把准备好竞争CPU运行的程序从辅存移到内存,这一过程又称换入。中级调度采用的就是交换技术。
例如,有一个CPU采用时间片轮转调度算法的多道程序环境。时间片到,内存管理器将刚刚执行过的进程换出,将另一进程换入刚刚释放的内存空间。同时,CPU调度器可以将时间片分配给其他已在内存中的进程。每个进程用完时间片都与另一“进程交换。在理想情况下,内存管理器的交换过程速度足够快,总有进程在内存中可以执行。
有关交换,需要注意以下几个问题:
- 交换需要备份存储, 通常是快速磁盘。它必须足够大,并提供对这些内存映像的直接访问。
- 为了有效使用CPU, 需要使每个进程的执行时间比交换时间长,而影响交换时间的主要是转移时间。转移时间与所交换的内存空间成正比。
- 若换出进程, 则必须确保该进程完全处于空闲状态。
- 交换空间通 常作为磁盘的一整块, 且独立于文件系统,因此使用起来可能很快。
- 交换通常 在有许多进程运行且内存空间吃紧时开始启动,而在系统负荷降低时就暂停。
- 普通的交换使用不多, 但交换策略的某些变体在许多系统(如UNIX系统)中仍发挥作用。
交换技术主要在不同进程(或作业)之间进行,而覆盖则用于同一个程序或进程中。由于覆盖技术要求给出程序段之间的覆盖结构,使得其对用户和程序员不透明,所以对于主存无法存放用户程序的矛盾,现代操作系统是通过虚拟内存技术来解决的,覆盖技术则已成为历史;而交换技术在现代操作系统中仍具有较强的生命力。
1.3 连续分配管理方式
连续分配方式是指为一个用户程序分配一个连续的内存空间,譬如某用户需要1GB的内存空间,连续分配方式就在内存空间中为用户分配一块连续的1GB空间。连续分配方式主要包括单一连续分配、 固定分区分配和动态分区分配。
1.3.1 单一连续分配
内存在此方式下分为系统区和用户区,系统区仅供操作系统使用,通常在低地址部分:用户区是为用户提供的、除系统区之外的内存空间。这种方式无须进行内存保护。因为内存中永远只有一道程序,因此肯定不会因为访问越界而干扰其他程序。
这种方式的优点是简单、无外部碎片,可以采用覆盖技术,不需要额外的技术支持。缺点是只能用于单用户、单任务的操作系统中,有内部碎片,存储器的利用率极低。
1.3.2 固定分区分配
固定分区分配是最简单的一种多道程序存储管理方式,它将用户内存空间划分为若千固定大小的区域,每个分区只装入一道作业。当有空闲分区时,便可再从外存的后备作业队列中选择适当大小的作业装入该分区,如此循环。
固定分区分配在划分分区时有两种不同的方法,如图所示。
- 分区大小相等。用于利用一台计算机去控制多个相同对象的场合,缺乏灵活性。
- 分区大小不等。 划分为多个较小的分区、适量的中等分区和少量大分区。
为便于内存分配,通常将分区按大小排队,并为之建立一张分区 说明表,其中各表项包括每个分区的始址、大小及状态(是否已分配),如下图(a)分区说明表所示。当有用户程序要装入时,便检索该表,以找到合适的分区给予分配并将其状态置为“已分配”;未找到合适分区时,则拒绝为该用户程序分配内存。存储空间的分配情况如图(b)存储空间分配情况所示。
这种分区方式存在两个问题:
- 程序可能太大而放不进任何一个分区中,这时用户不得不使用覆盖技术来使用内存空间;
- 主存利用率低,当程序小于固定分区大小时,也占用一个完整的内存分区空间,这样分区内部就存在空间浪费,这种现象称为内部碎片。
固定分区是可用于多道程序设计的最简单的存储分配,无外部碎片,但不能实现多进程共享一个主存区,所以存储空间利用率低。固定分区分配很少用于现在通用的操作系统中,但在某些用于控制多个相同对象的控制系统中仍发挥着一定的作用。
1.3.3 动态分区分配
动态分区分配又称可变分区分配,是一种动态划分内存的分区方法。这种分区方法不预先划分内存,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此,系统中分区的大小和数目是可变的。
如图所示,系统有64MB内存空间,其中低8MB固定分配给操作系统,其余为用户可用内存。开始时装入前三个进程,它们分别分配到所需的空间后,内存只剩下4MB,进程4无法装入。在某个时刻,内存中没有一个就绪进程,CPU 出现空闲,操作系统就换出进程2,换入进程4。由于进程4比进程2小,这样在主存中就产生了一个6MB的内存块。之后CPU又出现空闲,而主存无法容纳进程2,操作系统就换出进程1,换入进程2。
动态分区在开始分配时是很好的,但之后会导致内存中出现许多小的内存块。随着时间的推移,内存中会产生越来越多的碎片(图中最后的4MB和中间的6MB,且随着进程的换入/换出,很可能会出现更多、更小的内存块),内存的利用率随之下降。这些小的内存块称为外部碎片,指在所有分区外的存储空间会变成越来越多的碎片,这与固定分区中的内部碎片正好相对。克服外部碎片可以通过紧凑(Compaction) 技术来解决,即操作系统不时地对进程进行移动和整理。但这需要动态重定位寄存器的支持,且相对费时。紧凑的过程实际上类似于Windows系统中的磁盘整理程序,只不过后者是对外存空间的紧凑。
在进程装入或换入主存时,若内存中有多个足够大的空闲块,则操作系统必须确定分配哪个内存块给进程使用,这就是动态分区的分配策略。考虑以下几种算法:
- 首次适应(First Fit)算法:空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。
- 最佳适应(Best Fit)算法:空闲分区按容量递增的方式形成分区链,找到第一个能满 足要求的空闲分区。
- 最坏适应(Worst Fit)算法:又称最大适应(Largest Fit)算法,空闲分区以容量递减的次序链接,找到第一个能满足要求的空闲分区,即挑选出最大的分区。
- 邻近适应(NextFit) 算法:又称循环首次适应算法,由首次适应算法演变而成。不同之处是,分配内存时从上次查找结束的位置开始继续查找。
首次适应算法不仅是最简单的,而且通常也是最好和最快的。在UNIX系统的最初版本中,就是使用首次适应算法为进程分配内存空间的,它使用数组的数据结构(而非链表)来实现。不过,首次适应算法会使得内存的低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此增加了查找的开销。
邻近适应算法试图解决这个问题。但实际上,它常常导致在内存的末尾分配空间(因为在一遍扫描中,内存前面部分使用后再释放时,不会参与分配)分裂成小碎片。它通常比首次适应算法的结果要差。
最佳适应算法虽然称为“最佳”,但是性能通常很差,因为每次最佳的分配会留下很小的难以利用的内存块,会产生最多的外部碎片。
最坏适应算法与最佳适应算法相反,它选择最大的可用块,这看起来最不容易产生碎片,但是却把最大的连续内存划分开,会很快导致没有可用的大内存块,因此性能也非常差。
Knuth和Shore分别就前三种方法对内存空间的利用情况做了模拟实验,结果表明:首次适应算法可能比最佳适应法效果好,而它们两者一定比最大适应法效果好。另外要注意,在算法实应算法可能比最佳适应法效果好,而它们两者一定比最大适应法效果好。另外要注意,在算法实现时,分配操作中最佳适应法和最大适应法需要对可用块进行排序或遍历查找,而首次适应法和邻近适应法只需要简单查找;在回收操作中,当回收的块与原来的空闲块相邻时(有三种相邻的情况,比较复杂),需要将这些块合并。在算法实现时,使用数组或链表进行管理。除了内存的利用率,这里的算法开销也是操作系统设计需要考虑的一个因素。
三种内存分区管理方式的比较
作业道数 | 内部碎片 | 外部碎片 | 硬件支持 | 可用空间管理 | 解决碎片方法 | 解决空间不足 | 提高作业道数 | |
单道连续分配 | 1 | 有 | 无 | 界地址寄存器、越界检查机构 | - | - | 覆盖 | 交换 |
多道固定连续分配 | <= N(用户空间划为N块) | 有 | 无 | ①上下界寄存器、越界检查机构 ②基地址寄存器、长度寄存器、动态地址转换机构 | - | - | ||
多道可变连续分配 | - | 无 | 有 | ①数组②链表 | 紧凑 |
以上三种内存分区管理方法有一个共同特点,即用户进程(或作业)在主存中都是连续存放的。这里对它们进行比较和总结。
1.4 非连续分配管理方式
非连续分配允许一个程序分散地装入不相邻的内存分区。在连续分配管理方式中,我们发现,即使内存有超过1GB的空闲空间,但若没有连续的10B空间;则需要1GB空间的作业仍然是无法运行的;但若采用非连续分配管理方式,则作业所要求的1GB内存空间可以分散地分配在内存的各个区域,当然,这也需要额外的空间去存储它们( 分散区域)的索引,使得非连续分配方式的存储密度低于连续存储方式的。
非连续分配管理方式根据分区的大小是否固定,分为分页存储管理方式和分段存储管理方式。
在分页存储管理方式中,又根据运行作业时是否要把作业的所有页面都装入内存才能运行,分为基本分页存储管理方式和请求分页存储管理方式。下面介绍基本分页存储管理方式。
1.4.1 基本分页存储管理方式
固定分区会产生内部碎片,动态分区会产生外部碎片,这两种技术对内存的利用率都比较低。
我们希望内存的使用能尽量避免碎片的产生,这就引入了分页的思想:把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位。每个进程也以块为单位进行划分,进程在执行时,以块为单位逐个申请主存中的块空间。
分页的方法从形式上看,像分区相等的固定分区技术,分页管理不会产生外部碎片。但它又有本质的不同点:块的大小相对分区要小很多,而且进程也按照块进行划分,进程运行时按块申请主存可用空间并执行。这样,进程只会在为最后一个不完整的块申请一个主存块空间时,才产生主存碎片,所以尽管会产生内部碎片,但这种碎片相对于进程来说也是很小的,每个进程平均只产生半个块大小的内部碎片(也称页内碎片)。
1.分页存储的几个基本概念:
- 页面和页面大小。
- 地址结构。
- 页表。
页面和页面大小
进程中的块称为页(Page), 内存中的块称为页框(Page Frame,或页帧)。外存也以同样的单位进行划分,直接称为块(Block)。 进程在执行时需要申请主存空间,即要为每个页面分配主存中的可用页框,这就产生了页和页框的一-- -对应。
为方便地址转换,页面大小应是2的整数幂。同时页面大小应该适中,页面太小会使进程的页面数过多,这样页表就会过长,占用大量内存,而且也会增加硬件地址转换的开销,降低页面换入换出的效率;页面过大又会使页内碎片增多,降低内存的利用率。所以页面的大小应该适中,要在空间效率和时间效率之间权衡。
地址结构
分页存储管理的逻辑地址结构如图所示:
地址结构包含两部分:前一部分为页号P,后一部分为页内偏移量w。地址长度为32位,其中0~11位为页内地址,即每页大小为4KB;12~31 位为页号,地址空间最多允许页。
注意,地址结构决定了虚拟内存的寻址空间有多大。在实际问题中,页号、页内偏移、逻辑地址大多都是用二进制数给出的。
页表
为了便于在内存中找到进程的每个页面所对应的物理块,系统为每个进程建立一张页表,它记录页面在内存中对应的物理块号,页表一般存放在内存中。
页表是由页表项组成的,初学者容易混淆页表项与地址结构,页表项与地址都由两部分构成,而且第一部分都是页号,但页表项的第二部分是物理内存中的块号,而地址的第二部分是页内偏移;页表项的第二部分与地址的第二部分共同组成物理地址。
在配置页表后,进程执行时,通过查找该表,即可找到每页在内存中的物理块号。可见,页表的作用是实现从页号到物理块号的地址映射,如图所示。
2.基本地址变换机构
地址变换机构的任务是将逻辑地址转换为内存中的物理地址。地址变换是借助于页表实现的,下图给出了分页存储管理系统中的地址变换机构。
在系统中通常设置一个页表寄存器(PTR),存放页表在内存的起始地址F和页表长度M。进程未执行时,页表的始址和长度存放在进程控制块中,当进程执行时,才将页表始址和长度存入页表寄存器。设页面大小为L,逻辑地址A到物理地址E的变换过程如下(逻辑地址、页号、每页的长度都是十进制数):
- 计算页号P (P=A/L)和页内偏移量W (W= A%L)。
- 比较页号P和页表长度M,若P≥M,则产生越界中断,否则继续执行。
- 页表中页号P对应的页表项地址=页表始址F+页号Px页表项长度,取出该页表项内容b,即为物理块号。要注意区分页表长度和页表项长度。页表长度的值是指一共有多少页,页表项长度是指页地址占多大的存储空间。
- 计算
,用得到的物理地址E去访问内存。
以上整个地址变换过程均是由硬件自动完成的。例如,若页面大小L为1KB, 页号2对应的物理块为b=8,计算逻辑地址A=2500的物理地址E的过程如下:
P= 2500/1K =2,
w= 2500%1K =452,
查找得到页号2对应的物理块的块号为8,
E= 8x1024 + 452 = 8644。
题目中条件用十进制数给出和用二进制数给出的处理过程会稍有不同。同时,页式管理只需给出一个整数就能确定对应的物理地址,因为页面大小L是固定的。因此,页式管理中地址空间是一维的。
页表项的大小不是随意规定的,而是有所约束的。如何确定页表项的大小?
页表项的作用是找到该页在内存中的位置。以32位逻辑地址空间、字节编址单位、一页4KB为例,地址空间内一共有页,因此需要
位才能保证表示范围能容纳所有页面,又因为以字节作为编址单位,即页表项的大小
。所以在这个条件下,为了保证页表项能够指向所有页面,页表项的大小应该大于3B,当然,也可选择更大的页表项让一个页面能够正好容下整数个页表项,进而方便存储(如取成4B,一页正好可以装下1K个页表项),或增加一-些其他信息。
下面讨论分页管理方式存在的两个主要问题:
- 每次访存操作都需要进行逻辑地址到物理地址的转换,地址转换过程必须足够快,否则访存速度会降低;
- 每个进程引入页表,用于存储映射机制,页表不能太大,否则内存利用率会降低。
3.具有快表的地址变换机构
由上面介绍的地址变换过程可知,若页表全部放在内存中,则存取一个数据或一条指令至少要访问两次内存:
- 第一次是访问页表,确定所存取的数据或指令的物理地址;
- 第二次是根据该地址存取数据或指令。
显然,这种方法比通常执行指令的速度慢了一半 。
为此,在地址变换机构中增设一个具有并行查找能力的高速缓冲存储器一快表, 又称相联存储器(TLB),用来存放当前访问的若干页表项,以加速地址变换的过程。与此对应,主存中的页表常称为慢表。具有快表的地址变换机构如下图所示。
在具有快表的分页机制中,地址的变换过程如下:
- CPU给出逻辑地址后,由硬件进行地址转换,将页号送入高速缓存寄存器,并将此页号与快表中的所有页号进行比较。
- 若找到匹配的页号,说明所要访问的页表项在快表中,则直接从中取出该页对应的页框号,与页内偏移量拼接形成物理地址。这样,存取数据仅一次访存便可实现。
- 若未找到匹配的负号,则需要访问主存中的页表,在读出页表项后,应同时将其存入快表,以便后面可能的再次访问。但若快表已满,则必须按照一定的算法对旧的页表项进行替换。
注意:有些处理机设计为快表和慢表同时查找,若在快表中查找成功则终止慢表的查找。
一般快表的命中率可达90%以上,这样分页带来的速度损失就可降低至10%以下。快表的有效性基于著名的局部性原理,后面讲解虛拟内存时将会具体讨论它。
4.两级页表
由于引入了分页管理,进程在执行时不需要将所有页调入内存页框,而只需将保存有映射关系的页表调入内存。但是,我们仍然需要考虑页表的大小。以32位逻辑地址空间、页面大小4KB、页表项大小4B为例,若要实现进程对全部逻辑地址空间的映射,则每个进程需要即约100万个页表项。也就是说,每个进程仅页表这一项就需要4MB主存空间,这显然是不切实际的。即便不考虑对全部逻辑地址空间进行映射的情况,一个逻辑地址空间稍大的进程,其页表大小也可能是过大的。以一个40MB的进程为例,页表项共40KB (40MB/4KBx4B), 若将所有页表项内容保存在内存中,则需要10个内存页框来保存整个页表。整个进程大小约为1万个页面,而实际执行时只需要几十个页面进入内存页框就可运行,但若要求10个页面大小的页表必须全部进入内存,则相对实际执行时的几十个进程页面的大小来说,肯定降低了内存利用率;从另一方面来说,这10页的页表项也并不需要同时保存在内存中,因为在大多数情况下,映射所需要的页表项都在页表的同一个页面中。
为了压缩页表,我们进一步延伸页表映射的思想,就可得到二级分页,即使用层次结构的页表:将页表的10页空间也进行地址映射,建立上一级页表,用于存储页表的映射关系。这里对页表的10个页面进行映射只需要10个页表项,所以上-一级页表只需要1页就已足够(可以存储= 1024个页表项)。在进程执行时,只需要将这一-页的 上一级页表调入内存即可,进程的页表和进程本身的页面可在后面的执行中再调入内存。根据上面提到的条件(32位逻辑地址空间、页面大小4KB、页表项大小4B,以字节为编址单位),我们来构造一个适合的页表结构。页面大小为4KB,页内偏移地址为
= 12位,页号部分为20位,若不采用分级页表,则仅页表就要占用20<4B/4KB = 1024 页,这大大超过了许多进程自身需要的页面,对于内存来说是非常浪费资源的,而且查询页表工作也会变得十分不便、试想若把这些页表放在连续的空间内,查询对应页的物理页号时可以通过页表首页地址+页号x4B的形式得到,而这种方法查询起来虽然相对方便,但连续的1024 页对于内存的要求实在太高,并且上面也说到了其中大多数页面都是不会用到的,所以这种方法并不具有可行性。若不把这些页表放在连续的空间里,则需要一张索 引表来告诉我们第几张页表该上哪里去找,这能解决页表的查询问题,且不用把所有的页表都调入内存,只在需要它时才调入(下节介绍的虚拟存储器思想),因此能解决占用内存空间过大的问题。读者也许发现这个方案就和当初引进页表机制的方式一模一样, 实际上就是构造一个页表的页表,也就是二级页表。为查询方便,顶级页表最多只能有1个页面(一定要记住这个规定),因此顶级页表总共可以容纳4KB/4B= 1K个页表项,它占用的地址位数为
= 10位,而之前已经计算出页内偏移地址占用了12位,因此一一个32位的逻辑地址空间就剩下了10位,正好使得二级页表的大小在一页之内,这样就得到了逻辑地址空间的格式,如图所示。
二级页表实际上是在原有页表结构上再加上一层页表,示意结构如下图所示。
建立多级页表的目的在于建立索引,以便不用浪费主存空间去存储无用的页表项,也不用盲目地顺序式查找页表项。
1.4.2 基本分程存储管理方式
分页管理方式是从计算机的角度考虑设计的,目的是提高内存的利用率,提升计算机的性能。分页通过硬件机制实现,对用户完全选明。分段管理方式的提出则考虑了用户和程序员,以摘足方便端程。信息保护和共学、动态增长及动念链核等多方面的需要。
分段
段式管理方式按照用户进程中的自然段划分理辑空间。
例如,用户进程由主程序、两个子程序。栈和一段数据组成,于是可以把这个用户进程划分为5段,每段从0开始编址,并分配一段连续的地址空间(段内要求连续。段间不要求连续,因此整个作业的地址空间是二维的),其逻辑地址由段号S与段内偏移量W两部分组成。
在下图中,段号为16位,段内偏移量为16位,因此一个作业最多有210 -65536段,最大段长为64KB。
在页式系统中,逻辑地址的页号和页内偏移量对用户是透明的,但在段式系统中。段号和段内偏移量必须由用户显式提供,在高级程序设计语言中,这个工作由编译程序完成。
段表
每个进程都有一张逻辑空间与内存空映射的段表。其中每个段表项对应进程的一段, 段表项记录该段在内存中的始址和长度。段表的内容如下图所示。
配置段表后,执行中的进程可通过查找段表,找到每段所对应的内存区。可见,段表用于实现从逻辑段到物理内存区的映射,如下图所示。
地址变换机构
分段系统的地址变换过程如下图所示。
为了实现进程从逻辑地址到物理地址的变换功能,在系统中设置了段表寄存器,用于存放段表始址F和段表长度M。从逻辑地址4到物理地址E之间的地址变换过程如F:
- 从逻辑地址A中取出前几位为段号S,后几位为段内偏移量W,注意在段式存储管理的题目中,逻辑地址一般以二进制数给出,而在页式存储管理中,逻辑地址一般以十进制数给出,要具体问题具体分析。
- 比较段号S和段表长度M,若S≥M,则产生越界中断,否则继续执行。
- 段表中段号S对应的段表项地址=段表始址F+段号Sx段表项长度,取出该段表项的前几位得到段长C。若段内偏移量≥C,则产生越界中断,否则继续执行。可以看出,段表项实际上只有两部分,前几位是段长,后几位是始址。
- 取出段表项中该段的始址b,计算E=b+ w,用得到的物理地址E去访问内存。
段的共享与保护
在分段系统中,段的共享是通过两个作业的段表中相应表项指向被共享的段的同一个物理副本来实现的。
当一个作业正从共享段中读取数据时,必须防止另一个作业修改此共享段中的数据。不能修改的代码称为纯代码或可重入代码(它不属于临界资源),这样的代码和不能修改的数据可以共享,而可修改的代码和数据不能共享。
与分页管理类似,分段管理的保护方法主要有两种:
- 一种是存取控制保护;
- 另一种是地址越界保护。
地址越界保护将段表寄存器中的段表长度与逻辑地址中的段号比较,若段号大于段表长度,则产生越界中断;再将段表项中的段长和逻辑地址中的段内偏移进行比较,若段内偏移大于段长,也会产生越界中断。
分页管理中的地址越界保护只需要判断页号是否越界,页内偏移是不可能越界的。
与页式管理不同,段式管理不能通过给出一个整数便确定对应的物理地址,因为每段的长度是不固定的,无法通过整数除法得出段号,无法通过求余得出段内偏移,所以段号和段内偏移一定要显式给出(段号,段内偏移),因此分段管理的地址空间是二维的。
1.4.3 段页式管理方式
页式存储管理能有效地提高内存利用率,而分段存储管理能反映程序的逻辑结构并有利于段的共享。
将这两种存储管理方法结合起来,便形成了段页式存储管理方式。
在段页式系统中,作业的地址空间首先被分成若干逻辑段,每段都有自己的段号,然后将每段分成若干大小固定的页。对内存空间的管理仍然和分页存储管理一样, 将其分成若干和页面大小相同的存储块,对内存的分配以存储块为单位,如下图所示。
在段页式系统中,作业的逻辑地址分为三部分:段号、页号和页内偏移量,如下图所示。
为了实现地址变换,系统为每个进程建立一张段表, 每个分段有一张页表。 段表表项中至少包括段号、页表长度和页表始址,页表表项中至少包括页号和块号。
此外,系统中还应有一个段表寄存器,指出作业的段表始址和段表长度(段表寄存器和页表寄存器的作用都有两个,一是在段表或页表中寻址,二是判断是否越界)。
注意:在一个进程中,段表只有一个,而页表可能有多个。
在进行地址变换时,首先通过段表查到页表始址,然后通过页表找到页帧号,最后形成物理地址。如下图所示,进行一次访问实际需要三次访间主存,这里同样可以使用快表来加快查找速度,其关键字由段号、页号组成,值是对应的页帧号和保护码。
结合上面对段式管理和页式管理的地址空间的分析,可以得出结论:段页式管理的地址空间是二维的。
2 虚拟内存管理
2.1 虛拟内存的基本概念
2.1.1 传统存储管理方式的特征
上面讨论的各种内存管理策略都是为了同时将多个进程保存在内存中,以便允许进行多道程序设计。它们都具有以下两个共同的特征:
- 一次性
- 驻留性
一次性
作业必须一次性全部装入内存后,才能开始运行。这会导致两种情况:
- 当作业很大而不能全部被装入内存时,将使该作业无法运行,
- 当大量作业要求运行时,由于内存不足以容纳所有作业,只能使少数作业先运行,导致多道程序度的下降。
驻留性
作业被装入内存后,就一直驻留在内存中,其任何部分都不会被换出,直至作业运行结束。运行中的进程会因等待I0而被阻塞,可能处于长期等待状态。
由以上分析可知,许多在程序运行中不用或暂时不用的程序(数据)占据了大量的内存空间,而一些需要运行的作业又无法装入运行,显然浪费了宝贵的内存资源。
2.1.2 局部性原理
要真正理解虚拟内存技术的思想,首先须了解著名的局部性原理。
Bill Joy (SUN公司CEO)说过:“在研究所时,我经常开玩笑地说高速缓存是计算机科学中唯一重要的思想。 事实上,高速缓存技术确实极大地影响了计算机系统的设计。”快表、页高速缓存及虚拟内存技术从广义上讲,都属于高速緩存技术。这个技术所依赖的原理就是局部性原理。局部性原理既适用于程序结构,又适用于数据结构(更远地讲,Dijkstra 关丁"goto 语句有害”的著名论文也出于对程序局部性.原理的深刻认识和理解)。
局部性原理表现在以下两个方面:
- 时间局部性:程序中的某条指令一 旦执行,不久后该指令可能再次执行:某数据被访问过,不久后该数据可能再次被访问。产生时间局部性的典型原因是程序中存在着大量的循环操作。
- 空间局部性:一旦程序访间了某个存储单元,在不久后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在-定的范围之内,因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、 数组、表等形式簇聚存储的。
时间局部性通过将近来使用的指令和数据保存到高速缓冲存储器中,并使用高速缓存的层次结构实现。空间局部性通常使用较大的高速缓存,并将预取机制集成到高速缓存控制逻辑中实现。虚拟内存技术实际上建立了“内存-外存”的两级存储器结构,利用局部性原理实现高速缓存。
2.1.3 虚拟存储器的定义和特征
基于局部性原理,在程序装入时,将程序的一部分装入内存, 而将其余部分留在外存,就可启动程序执行。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另-方面,操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的信息。这样,系统好像为用户提供了- -个比实际内存大得多的存储器,称为虚拟存储器。
之所以将其称为虚拟存储器,是因为这种存储器实际上并不存在,只是由于系统提供了部分装入、请求调入和置换功能后(对用户完全透明),给用户的感觉是好像存在一个比实际物理内春大得多的存储器。虚拟存储器的大小由计算机的地址结构决定,并不是内存和外存的简单相加。
虛拟存储器有以下三个主要特征
- 多次性:多次性是指无须在作业运行时一次性地全部装入内存,而允许被分成多次调入内存运行。
- 对换性:对换性是指无须在作业运行时一直常驻内存,而允许在作业的运行过程中,进行换进和换出。
- 虚拟性:虚拟性是指从逻辑上扩充内存的容量,使用户所看到的内存容量远大于实际的内存容量。
2.1.4 虚拟内存技术的实现
虚拟内存技术允许将一个作业分多次调入内存。采用连续分配方式时,会使相当一部分内存空间都处于暂时或“永久”的空闲状态,造成内存资源的严重浪费,而且也无法从逻辑上扩大内存容量。因此,虚报内存的实现需要建立在离散分配的内存管理方式的基础上。
虚拟内存的实现有以下三种方式
- 请求分页存储管理。
- 请求分段存储管理。
- 请求段页式存储管理。
不管哪种方式,都需要有一定的硬件支持。一般需要的支持有以下几个方面
- 一定容量的内存和外存。
- 页表机制(或段表机制)作为主要的数据结构。
- 中断机构,当用户程序要访问的部分尚未调入内存时,则产生中断。
- 地址变换机构, 逻辑地址到物理地址的变换。
2.2 请求分页管理方式
请求分页系统建立在基本分页系统基础之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虛拟存储器的方法。
在请求分页系统中,只要求将当前需要的一部分页面装入内存,便可以启动作业运行。在作业执行过程中,当所要访间的页面不在内存中时,再通过调页功能将其调入,同时还可通过置换功能将暂时不用的页面换出到外存上,以便腾出内存空间。
为了实现请求分页,系统必须提供一-定的硬件支持。 除了需要一定容量的内存及外存的计算机系统,还需要有页表机制、缺页中断机构和地址变换机构。
2.2.1 页表机制
请求分页系统的页表机制不同于基本分页系统,请求分页系统在一个作业运行之前不要求全部一次性调入内存,因此在作业的运行过程中,必然会出现要访问的页面不在内存中的情况,如何发现和处理这种情况是请求分页系统必须解决的两个基本问题,为此,在请求页表项中增加了4个字段,如下图所示。
增加的4个字段说明如下
- 状态位P:用于指示该页是否已调入内存,供程序访问时参考。
- 访问字段 A:用于记录本页在一段时间内被访问的次数,或记录本页最近已有多长时间未被访问,供置换算法换出页面时参考。
- 修改位 M:标识该页在调入内存后是否被修改过。
- 外存地址:用于指出该页在外存上的地址,通常是物理块号,供调入该页时参考。
2.2.2 缺页中断机构
在请求分页系统中,每当所要访问的页面不在内存中时,便产生一个缺页中断, 请求操作系统将所缺的页调入内存。此时应将缺页的进程阻塞(调页完成唤醒),若内存中有空闲块,则分配一个块,将要调入的页装入该块,并修改页表中的相应页表项,若此时内存中没有空闲块,则要淘汰某页(若被淘汰页在内存期间被修改过,则要将其写回外存)。
缺页中断作为中断,同样要经历诸如保护CPU环境、分析中断原因、转入缺页中断处理程序、恢复CPU环境等几个步骤。
但与一般的中断相比,它有以下两个明显的区别
- 在指令执行期间而非 -条指令执行完后产生和处理中断信号,属于内部中断。
- 一条指令在执行期间,可能产生多次缺页中断。
2.2.3 地址变换机构
请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,为实现虚拟内存,又增加了某些功能而形成的。
如下图所示,在进行地址变换时,先检索快表:
- 若找到要访问的页,则修改页表项中的访问位(写指令还需要重置修改位),然后利用页表项中给出的物理块号和页内地址形成物理地址。
- 若未找到该页的页表项, 则应到内存中去查找页表,再对比页表顶中的状态位P,看该页是否已调入内存,未调入则产生缺页中断,请求从外存把该页调入内存。
2.3 页面置换算法(决定应该换入哪页、换出哪页)
进程运行时,若其访问的页面不在内存中而需将其调入,但内存已无空闲空间时,就需要从内存中调出一页程序或数据,送入磁盘的对换区。
选择调出页面的算法就称为页面置换算法。好的页面置换算法应有较低的页面更换频率,也就是说,应将以后不会再访问或以后较长时间内不会再访间的页面先调出。
常见的置换算法有以下4种:
- 最佳(OPT)置提算法
- 先进先出(FIFO) 页面置换算法
- 最近最久未使用(LRU)置换算法
- 时钟(CLOCK) 置换算法
2.3.1 最佳(OPT)置换算法
最佳(Optimal, 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 淘汰......以此类推,如下图所示,从图中可以看出采用最佳置换算法时的情况。
最长时间不被访问和以后被访问次数最小是不同的概念,初学者在理解OPT算法时千万不要混滑。
可以看到,发生缺页中断的次数为 9 ,页面置换的次数为 6 。
2.3.2 先进先出(FIFO) 页面置换算法
优先淘汰最早进入内存的页面,即在内存中驻留时间最久的页面。该算法实现简单,只需把调入内存的页面根据先后次序链接成队列,设置一个指针总指向最早的页面。但该算法与进程实际运行时的规律不适应,因为在进程中,有的页面经常被访问。
这里仍用上面的实例采用FIFO算法进行页面置换。进程访向页面 2 时,把最早进入内存的页面 7 换出。然后访问页面 3 时,把 2, 0,1 中最先进入内存的页面 0 换出。由下图以看出,利用FIFO算法时进行了12次页面置换,比最佳置换算法正好多一倍。
FIFO算法还会产生所分配的物理块数增大而页故障数不减反增的异常现象,这由Belady于1969年发现,因此称为Belady异常。只有FIFO算法可能出现Belady异常,LRU和OPT算法永远不会出现Belady异常。
如下图所示,页面访问顺序为3,2,1,0,3,2,4,3,2,1,0,4。若采用FIFO置换算法,当分配的物理块为3个时,缺页次数为9次;当分配的物理块为4个时,缺页次数为10次。分配给进程的物理块增多。但缺页次数不减反增。
2.3.3 最近最久未使用(LRU)置换算法
选择最近最长时间未访问过的页面予以淘汰,它认为过去一段时间内未访问过的页面,在最近的将来可能也不会被访问。该算法为每个页面设置一个访问字段,来记录页面自上次被访间以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。
再对上面的实例采用LRU算法进行页面置换,如下图所示。进程第一次对页面2访间时,将最近最久未被访问的页面7置换出去。然后在访问页面3时,将最近最久未使用的页面1换出。
从图中可以看出,前5次置换的情况与最佳置换算法相同,但两种算法并无必然联系。实际上,LRU算法根据各页以前的情况,是“向前看”的。而最佳置换算法则根据各页以后的使用情况,是“向后看”的。
LRU算法的性能较好,但需要寄存器和栈的硬件支持。LRU是堆栈类的算法。理论上可以证明,堆栈类算法不可能出现Belady异常。FIFO 算法基于队列实现,不是堆栈类算法。
2.3.4 时钟(CLOCK) 置换算法(最近未用算法, Not RecntyUsed,,NRU)
LRU算法的性能接近于OPT算法,但实现起来比较困难,且开销大;FIFO 算法实现简单,但性能差。因此,操作系统的设计者尝试了很多算法,试图用比较小的开销接近LRU算法的性能,这类算法都是CLOCK算法的变体。因为算法要循环扫描缓冲区,像时钟的指针一样转动, 所以称为CLOCK算法。
简单的CLOCK算法给每帧关联一个附加位。称为使用位。当某页首次装入主存时,将该帧的使用位设置为1;当该页随后再被访问到时,其使用位也被置为1。对于页替换算法,用于替换的候选械集合可视为一个循环缓冲区,并有一个指针与之相关联,当某一页被替换时,该指针披设置成指向缓冲区中的下一帧。当需要替换一页时,操作系统扫描缓冲区,以查找使用位被置为0的一帧每当遇到一个使用位为1的帧时,操作系统就将该位重新置为0;若在这个过程开始时,缓冲区中所有帧的使用位均为0,则选择遇到的第一个帧替换;若所有帧的使用位均为1,则指针在缓冲区中完整地循环一周,把所有使用位都置为0,并停留在最初的位置上,替换该帧中的页。由于该算法循环检查各页面的情况,因此称CLOCK算法,又称最近未用( Not RecntyUsed, NRU) 算法。
CLOCK算法的性能比较接近LRU算法,而通过增加使用的位数目,可以使得CLOCK算法更加高效。在使用位的基础上再增加一个修改位,则得到改进型CLOCK置换算法。这样,每帧都处于以下4种情况之一:
- 最近未被访问,也未被修改(u=0,m=0)。
- 最近被访问。但未被修改(u=1,m=0)。.
- 最近未被访问,但被修改(u=0,m=1)。
- 最近被访问,被修改(u=1,m=1)。
算法执行如下操作步骤:
- 从指针的当前位置开始。扫描帧缓冲区。在这次扫描过程中,对使用位不做任何修改。选择遇到的第一个帧(u=0,m=0)用于替换。.
- 若第1步失败,则重新扫描,查找(u=0,m=1)的帧。选择遇到的第一个这样的帧用于替换。在这个扫描过程中,对每个跳过的帧,把它的使用位设置成0。
- 若第2步失败,则指针将回到它的最初位置,且集合中所有顿的使用位均为0。重复第1步,并且若有必要,重复第2步,以便可以找到供替换的帧。
改进型CLOCK算法优于简单CLOCK算法的地方在于替换时首选没有变化的页。由于修改过的页在被替换之前必须写回。因而这样做会节省时间。
CLOCK算法和改进型CL0CK算法记忆起来不易。为方便记忆,我们将其总结如下。
操作系统中任何经过优化而有效的贝面置换算法都有一个原则,即尽可能保留曾经使用过的页面,而淘汰未使用的页面,认为这样可以在总体上减少换页次数。CLOCK算法只考虑到是否被访问过,因此被访问过的当然尽可能留下,未使用过的就淘汰;而改进型CLOCK算法对使用过的页面又做了细分,分为使用过但未修改过和使用过且修改过。因此,若有未使用过的页面,则当然首先把它换出,若全部页面都使用过,则当然优先把未修改过的页面换出。
这里举一个例子。 如下图所示,假设系统给某进程分配了5个页框,刚开始,进程依次访问1,3,4,2,5号页面,系统会将这些页面连成一个循环队列,刚开始扫描指针指向刚开始扫描时指针指向的页面第一个被访问的页面(即1号页)。
图3.26中小括号内的数字就是使用位。接下来。若进程请求访问6号页面,则由于此时分配给进程的5个页框都被使用,因此必须选择一一个页面置 换出去。按照CLOCK置换算法的规则,在第一轮扫描中,指针扫过的页面的使用位应置为0。第一轮扫描的过程如下图所示。
第一轮扫描中,未找到使用位为0的页面,因此需要进行第二轮扫描。第二轮扫描中。1号页面的使用位为0,因此将1号页面换出,将6号页面换入,将6号页的访问位设置为1,并将扫描指针后移(若下次需要换出页面,则从3号页面开始扫描),如下图所示。
注意一个小细节:假设1号页面原先占有的是x号物理块(页框),则6号页面换入内存后也放在x号物理块中。
2.4 页面分配策略
2.4.1 驻留集大小
对于分页式的虚拟内存,在进程准备执行时,不需要也不可能把一个进程的所有页都读入主存。因此,操作系统必须决定读取多少页,即决定给特定的进程分配几个页框。给一个进程分配的物理页框的集合就是这个进程的驻留集。需要考虑以下几点:
- 分配给一个进程的存储量越小,任何时候驻留在主存中的进程数就越多,从而可以提高处理机的时间利用效率。
- 若一个进程在主存中的页数过少,则尽管有局部性原理,页错误率仍然会相对较高。
- 若页数过多,则由于局部性原理,给特定的进程分配更多的主存空间对该进程的错误率没有明显的影响。
基于这些因素,现代操作系统通常采用三种策略:
- 固定分配局部置换
- 可变分配全局置换
- 可变分配局部置换
固定分配局部置换
它为每个进程分配一定数目的物理块,在整个运行期间都不改变。若进程在运行中发生缺页,则只能从该进程在内存中的页面中选出一页换出, 然后调入需要的页面。实现这种策略时,难以确定应为每个进程分配的物理块数目:太少会频繁出现缺页中断,太多又会使CPU和其他资源利用率下降。
可变分配全局置换
这是最易于实现的物理块分配和置换策略,它为系统中的每个进程分配一定数目的物理块,操作系统自身也保持一个空闲物理块队列。当某进程发生缺页时,系统从空闲物理块队列中取出-一个物理块分配给该进程,并将欲调入的页装入其中。这种方法比固定分配局部置換更加灵活,可以动态增加进程的物理块,但也存在弊端,如它会育目地给进程增加物理块,从而导致系统多道程序的并发能力下降。
可变分配局部置换
它为每个进程分配一定数目的物理块,当某个进程发生缺页时,只允许从该进程在内存的页面中选出一页换出。因此不会影响其他进程的运行。若进程在运行中频繁地缺页,则系统再为该进程分配若干物理块,直至该进程缺页率趋于适当程度;反之,若进程运行中的缺页率特别低,则可适当减少分配给该进程的物理块。比起可变分配全局置换,这种方法不仅可以动态增加进程物理块的数量,还能动态减少进程物理块的数量,在保证进程不会过多地调页的同时,也保持了系统的多道程序井发能力。当然它需要更复杂的实现,也需要更大的开销,但对比频繁地换入/换出所浪费的计算机资源,这种牺牲是值得的。
2.4.2 调入页面的时机
为确定系统将进程运行时所缺的页面调入内存的时机,可采取以下两种调页策略:
- 预调页策略
- 请求调页策略
预调页策略
根据局部性原理,一次调入若干相邻的页可能会比一次调入一页更高效。但若调入的一批页面中大多数都未被访问,则又是低效的。因此,需要采用以预测为基础的预调页策略,将预计在不久之后便会被访问的页面预先调入内存。但目前预调页的成功率仅约50%。因此这种策略主要用于进程的首次调入,由程序员指出应先调入哪些页。
请求调页策略
进程在运行中需要访问的页面不在内存而提出请求,由系统将所需页面调入内存。由这种策略调入的页一定会被访问,且这种策略比较易于实现,因此在目前的虚拟存储器中大多采用此策略。它的缺点是每次只调入一页,调入/调出页面数多时会花费过多的I/O开销。
预调入实际上就是运行前的调入,请求调页实际上就是运行期间调入。一般情况下,两种调页策略会同时使用。
2.4.3 从何处调入页面
请求分页系统中的外存分为两部分:
- 用于存放文件的文件区
- 用于存放对换页面的对换区
对换区通常采用连续分配方式,而文件区采用离散分配方式,因此对换区的磁盘I/O速度比文件区的更快。
这样,从何处调入页面就存在三种情况:
- 系统拥有足够的对换区空间
- 系统缺少足够的对换区空间
- UNIX方式
系统拥有足够的对换区空间
可以全部从对换区调入所需页面,以提高调页速度。为此,在进程运行前,需将与该进程有关的文件从文件区复制到对换区。
系统缺少足够的对换区空间
凡不会被修改的文件都直接从文件区调入;面当换出这些页面时,由于它们未被修改而不必再将它们换出。但对于那些可能被修改的部分,在将它们换出时领调到对换区,以后需要时再从对换区调入(因为读的速度比写的速度快)。
UNIX方式
与进程有关的文件都放在文件区,因此未运行过的页面都应从文件区调入。曾经运行过但又被换出的页面。由于放在对换区,因此下次调入时应从对换区调入。进程请求的共享页面若被其他进程调入内存,则无须再从对换区调入。
2.5 抖动
在页面置换过程中,一种最糟糕的情形是,刚刚换出的页面马上又要换入主存,刚刚换入的页面马上又要换出主存,这种频繁的页面调度行为称为抖动或颠簸。若一个进程在换页上用的时间多于执行时间,则这个进程就在颠簸。
频繁发生缺页中断(抖动)的主要原因是:某个进程颊繁访问的页面数目高于可用的物理页帧数目。
虚拟内存技术可在内存中保留更多的进程以提高系统效率。在稳定状态,几乎主存的所有空间都被进程块占据,处理机和操作系统可以直接访问到尽可能多的进程。然而,如果管理不当,那么处理机的大部分时间都将用于交换块,即请求调入页面的操作,而不是执行进程的指令,因此会大大降低系统效率。
2.6 工作集
工作集是指在某段时间间隔内,进程要访问的页面集合。基于局部性原理,可以用最近访问过的页面来确定工作集。一般来说,工作集W可由时间 t 和工作集窗口大小来确定。例如,某进程对页面的访间改序如下:
假设系统为该进程设定的工作集窗口大小为5,则在
时刻,进程的工作集为{2,3,5},在
时刻,进程的工作集为{1,2,3,4}。
实际应用中,工作集窗口会设置得很大,即对于局部性好的程序,工作集大小一般会比工作集窗口小很多。工作集反映了进程在接下来的一段时间内很有可能会频繁访问的页面集合,因此,若分配给进程的物理块小于工作集大小,则该进程就很有可能频繁缺页,所以为了防止这种抖动现象,一般来说分配给进程的物理块数(即驻留集大小)要大于工作集大小。
工作集模型的原理是,让操作系统跟踪每个进程的工作集,并为进程分配大于其工作集的物理块。落在工作集内的页面需要调入驻留集中,而落在工作集外的页面可从驻留集中换出。若还有空闲物理块,则可以再调一个进程到内存以增加多道程序数。若所有进程的工作集之和超过了可用物理块的总数,则操作系统会暂停一个进程,将其页面调出并将其物理块分配给其他进程,防止出现抖动现象。
2.7 地址翻译
引入一个实例来说明虚实地址的变换过程。设某系统满足以下条件:
- 有一个TLB与一个data Cache
- 存储器以字节为编址单位
- 虚拟地址14位
- 物理地址 12位
- 页面大小为 64B
- TLB为四路组相联,共有16个条目
- data Cache是物理寻址、直接映射的,行大小为4B,共有16组
写出访问地址为0x03d4, 0x00f1和0x0229的过程:
因为本系统以字节编址,页面大小为64B,则页内偏移地位为位,所以虚拟页号为14-6=8位,物理页号为12-6=6位。因为TLB为四路组相联,共有16个条目。则TLB共有16/4=4姐,因此虚拟页号中低
位就为组索引,高6位就为TLB标记。又因为Cacbe行大小为4B,因此物理地址中低
位为块偏移,Cache 共有16组,可知接下来
位为组索引,剩下高6位作为标记。地址结构如下图所示。
TLB表
页表
data Cache内容
先把十六进制的虚地址0x03d4, 0x00f1和0x0229转化为二进制形式,如下所示:
得到每个地址的组索引和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中,物理地址结构如下所示。
对于0x354, Cache索引为5, Cache标记为0x0d,对照Cache中索引为5的行,标记正好为0d,有效位为1,可知该块在Cache中,偏移0,即块0,可得虚拟地址0x03d4的内容为36H。
对于0x0bI, Cache索引为c, Cache 标记为0x02,对照Cache中索引为c的行,有效位为0,可知该块不在Cache中,要去主存中查我物理页号为2,偏移为0x31的内容。
查找顺序是从TLB到页表(TLB不命中),再到Cache和主存,最后到外存。
参阅:王道操作系统