操作系统(三)内存管理

基本概念

为什么要进行内存管理?

在单道批处理系统阶段,比如DOS系统,一个系统在一个时间段内只执行一个程序,整个内存都是一个程序,随便它怎么用。

引入多道程序的并发执行后,进程之间共享的不仅仅是处理机,还有主存储器。若不对内存进行管理,则容易导致内存数据的混乱,以至于限制进程的并发执行。因此,为了更好地支持多道程序并发执行,必须进行内存管理。

存储器的层次结构

对于存储器,我们需要速度,也需要容量,但在价格一定的情况下,这二者必然是成反比的,所以我们需要采用多级存储结构

在存储层次中越往上,存储介质的访问速度越快,价格也越高,相对存储容量也越小,寄存器、高速缓存、主存储器和磁盘缓存均属于操作系统存储管理的管辖范畴,对普通用户是透明的,具有掉电易失性。固定磁盘和可移动存储介质属于设备管理的管辖范畴,掉电不易失。

在这里插入图片描述

主存和辅存之间的数据调动则是由硬件和操作系统共同完成的,对应用程序员是透明的;CPU与Cache、主存与Cache之间的数据调动是由硬件自动完成的,对所有程序员均是透明的。

在分层存储系统中,上一层中的内容都只是下一层中内容的副本,例如 Cache(或主存)中的内容只是主存(或辅存)中内容的一部分。

为什么外存访问这么“慢”?

在这里插入图片描述

CPU寄存器和主存又被称为可执行存储器,可以被CPU直接访问;对辅存的访问则涉及到中断、设备驱动程序以及物理设备的运行,所需耗费的时间远远高于对可执行存储器访问的时间。

程序的链接和装入

在多道程序环境下,要使程序运行,必须先为之创建进程。而创建进程的第一件事,便是将程序和数据装入内存。如何将一个用户源程序变为一个可在内存中执行的程序,通常都要经过以下几个步骤:首先是要编译,由编译程序 Compile 将用户源代码编译成若干个目标模块;其次是链接,由链接程序 Linker 将编译后形成的一组目标模块,以及它们所需要的库函数链接在一起,形成一个完整的装入模块(可执行文件);最后是装入,由装入程序 Loader 将装入模块装入内存。

编译

**基本任务:**将用户源代码编译成若干个目标模块

我们通常意义上说的编译,其实和这里的编译不太相同,拿编译器来说,我们点击"run"后,会直接出来一个控制台程序,它其实是完成了:编译、汇编、链接、装入、执行。这里的编译是指包含了词法分析、语法分析、语义检测,中间代码生成,目标代码生成与优化、以及符号表管理与出错管理的过程。

链接

**基本任务:**源程序经过编译后,得到一组目标模块,再利用链接程序将这组目标模块链接起来,形成一个完整的装入模块(即可执行文件)

为什么需要链接?什么情况下不需要进行链接?

在我们的实际开发中,不可能将所有代码放在一个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,如一个源文件可能要调用另一个源文件中定义的函数,但是每个源文件都是独立编译的,即每个.c文件会形成一个.o文件,为了满足前面说的依赖关系,则需要将这些源文件产生的目标文件进行链接,从而形成一个可以执行的程序。这个过程就是链接。

假如说,只有一个.c文件,什么库函数,头文件都不用,那么就只有一个目标模块,不需要进行链接。

链接具体需要做哪些工作?

将各个模块之间相互引用的部分正确的衔接起来

把一些指令对其他符号地址的引用(变量、函数)加以修正

重新计算各个目标的地址,因为每个模块的地址都是从零开始的逻辑地址,而要把它们链接成一个可执行文件,就需要重新计算,形成新的逻辑地址

静态链接

在程序运行之前,将各目标模块及它们所需的库函数,链接成一个完整的装配模块,不再拆开

优点:

  • 在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快

缺点:

  • 浪费空间【如果多个程序对同一个目标文件都有依赖,那么内存中就会存在多个该目标文件的副本】
  • 更新困难【因为每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序】

动态链接

假设现在有两个程序program1.o和program2.o,这两者共用同一个库lib.o,假设首先运行程序program1,系统首先加载program1.o,当系统发现program1.o中用到了lib.o,系统接着加载lib.o,如果program1.o和lib.o还依赖于其他目标文件,则依次全部加载到内存中。当program2运行时,同样的加载program2.o,发现program2.o依赖于lib.o,但是此时lib.o已经存在于内存中,这个时候就不再进行重新加载,而是将内存中已经存在的lib.o映射到program2的虚拟地址空间中,从而进行链接。这个过程如果在装入时进行,就是“装入时动态链接”,如果在运行时进程,就是“运行时动态链接”。

优点:

  • 便于实现对目标模块的共享【不会像静态链接那样在内存中存在目标文件的多个副本】
  • 便于修改和更新【更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍】

缺点:

  • 性能会有一定损失【因为把链接推迟到了程序执行/装入时,所以每次执行/装入程序都需要进行链接,所以性能会有一定损失。据测试,动态链接和静态链接相比,性能损失大约在5%以下。这点性能损失用来换区程序在空间上的节省和程序构建和升级时的灵活性是值得的。】

装入时动态链接

将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的链接方式

存在问题:

在许多情况下,应用程序在运行时,每次要运行的模块可能是不相同的。但由于事先无法知道本次要运行哪些模块,故只能是将所有可能要运行到的模块都全部装入内存,并在装入时全部链接在一起。显然这是低效的,因为往往会有些目标模块根本就不运行。比较典型的例子是作为错误处理用的目标模块,如果程序在整个运行过程中都不出现错误,则显然就不会用到该模块。 运行时动态链接就是为了解决这些问题。


运行时动态链接

指对某些目标模块的链接,是在程序执行中需要该(目标)模块时,才对它进行的链接

动态链接库 DLL

动态链接库(Dynamic Link Library DLL),是微软公司在微软Windows操作系统中,实现共享函数库概念的一种方式,多个应用程序可同时访问内存中单个 DLL 副本的内容

装入

**基本任务:**将链接形成的装入模块装入内存,完成逻辑地址到物理地址的转换。

绝对装入

在编译阶段就把物理地址计算好。在编译时,如果知道程序将驻留在内存的什么位置,那么,编译程序将产生绝对地址的目标代码,程序中的逻辑地址与实际内存地址完全相同,装入内存时,不须对程序和数据的地址进行修改。

常用于Boot程序,嵌入式系统


可重定位装入(静态重定位)

“重定位”指的是将逻辑地址转换为物理地址

地址变换是在装入时一次完成的,编译、链接后的装入模块的地址都是从0开始的逻辑地址。装入时对地址进行“重定位”,将逻辑地址变换为物理地址

因为地址转换要求装入时就完成,要求作业装入内存时,就分配其需要的全部内存空间,如果没有足够的内存,就不能装入该作业,并且作业一旦进入内存后,在运行期间就不能再移动,也不能再申请内存空间


动态运行时装入(动态重定位)

编译、链接后的装入模块的地址也是从0开始的逻辑地址。装入程序把装入模块装入内存后,不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。在需要访问指令中某个地址的内存单元,则需要把地址与重定位寄存器中的值相加,来获得实际地址。这种方式需要一个重定位寄存器(基址寄存器)的支持

采用动态重定位时允许程序在内存中发生移动,允许进程实体的数据部分换入换出,修改基址寄存器中的地址即可【基于动态重定位才能实现内存管理中的”紧凑“以及请求分页管理方式】

内存保护

保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响

内存保护需要OS和硬件合作完成,内存保护属于内存管理的一项任务,但出于安全性和效率考虑(硬件效率高且出错概率低),采用硬件实现(使用重定位寄存器和界地址寄存器实现地址转换和越界判断)

内存保护举例:

在这里插入图片描述

内存空间分配策略

连续分配方式

单一连续分配

用于单用户、单任务的操作系统,无需内存保护机制,因为内存中只有一道程序,可能出现用户程序破坏操作系统,但后果也并不严重,只需要重启把OS重新装入内存即可

存在问题:

  • 有内部碎片,只适用于单用户、单任务的OS,存储器利用率极低

固定分区分配

最简单(也是最早的)的可运行多道程序的存储管理方式,将内存用户空间划分为若干个固定大小的区域,在每个分区中只装入一道作业,这样,把用户空间划分为几个分区,便允许有几道作业并发运行。

除去利用一台计算机去控制多个相同对象这样的特殊场景场合,一般都内存划分成含有多个较小的分区、适量的中等分区及少量的大分区

管理方式

使用一张分区说明表,记录每个分区的始址、大小及状态(是否分配)

存在问题

  • 程序太大而放不进任何一个分区,不得不使用覆盖技术,降低性能

  • 存在内部碎片(没有外部碎片),主存利用率低

动态分区分配(可变分区分配)

根据进程的实际需要,动态地为之分配内存空间,使用动态分区在开始分配时是很好的,之后或多或少都会导致内存中出现小碎片,且会越来越多,可以通过“紧凑”方式把分散的小分区拼接成大分区(需要支持动态重定位)

空闲分区表:记录每个空闲分区的情况。每个空闲分区占一个表目,表目中包括分区序号、分区始址及分区的大小等数据项

空闲分区链:双向链表,所有的空闲分区首尾链接

分区分配算法

首次适应算法 first fit

顺序查找第一个能满足的空闲分区,进行分配,剩余部分仍留在空闲链中,最简单的,但实际效果也是最好的

存在问题:

空闲分区以地址递增次序链接,该算法倾向于优先利用内存中低址部分的空闲分区,从而保留了高址部分的大空闲区。这给为以后到达的大作业分配大的内存空间创造了条件,但低址部分会留下许多难以利用的小空闲分区,而每次查找又都是从低址部分开始,这无疑也增加了查找可用空闲分区时的开销。


最佳适应算法 best fit

空闲分区以容量递增次序链接,分配完成后需要调整空闲表的顺序

存在问题:

存储器中会留下越来越多难以利用的小空闲区


最坏适应算法 worst fit

空闲分区以容量递减次序链接,分配完成后需要调整空闲表的顺序,最坏适应分配算法查找效率很高,因为链接分区的顺序是按容量递减的,要么第一个分配,要么不分配

存在问题:

这种策略使剩下的空闲区不至于太小,但也使得存储器中缺乏大的空闲分区,可能无法满足大进程


循环首次适应算法/邻近适应 next fit

由首次适应算法演变而成的。接着上次找到位置开始查找,一定程度上解决了首次适应算法存在的问题,理想情况下,使内存中的空闲分区分布得更均匀,从而减少了查找空闲分区时的开销

事实上,很难做到均匀,因为在一趟扫描过程中,内存的前面部分会使用后再释放

非连续(离散)分配方式

连续分配方式会形成许多外部“碎片” ,虽然可通过“紧凑”方法将许多碎片拼接成可用的大块空间,但须为之付出很大开销。如果允许将一个进程直接分散地装入到许多不相邻接的分区中,则无须再进行“紧凑” (虽然离散分配会产生内部碎片,但这种碎片相对于进程来说是很小的),基于这一思想而产生了离散分配方式。如果离散分配的基本单位是页,则称为分页存储管理方式;如果离散分配的基本单位是段,则称为分段存储管理方式。

在分页存储管理方式中,如果不具备页面对换功能,则称为基本的分页存储管理方式,或称为纯分页存储管理方式,它不具有支持实现虚拟存储器的功能,它要求把每个作业全部装入内存后方能运行。与之对应的是请求调页。


一些基本概念

页,页面

将一个进程的逻辑地址空间分成若干个大小相等的片段

虚拟存储器中的"块"(页面大小)

进程中称作“页”,内存中称作“页框”,‘页帧“(这个不是主存-Cache层次的内存块),外存中直接称作“块”(这个也不是磁盘块)【内存块以及磁盘块它们不需要和这个“块”有什么关系,因为页面的概念只用于进程层次(有点偏软件),这两个块只涉及硬件,比如Cache中调入了一个内存块,它可能包含很多个页面,它并不关心这些页面有什么】

页表

系统为每个进程建立的一张实现从页号到物理块号的地址映射表,进程的页表是一般是常驻内存的(多级页表,只有顶级页表常驻内存),其始址存放在进程的PCB中,上处理机的进程会把地址写入页表基址寄存器 PTB


基本分页存储管理方式

逻辑地址结构

页号 + 页内偏移量

在这里插入图片描述

页面大小的选择

页面太大

  • 主存中放入的页面数量减少,可能导致缺页频率增高
  • 换页代价增大

页面太小

  • 没有很好的满足局部性原理

  • 页表项过多,搜索速度变慢

页表项大小的选择

页表项的作用是找到该页在内存中的位置。以 32 32 32 位逻辑地址空间、按字节编址、一页 4 K B 4KB 4KB 为例,地址空间内一共有 2 32 B 4 K B = 1 M \frac{2^{32}B}{4KB}=1M 4KB232B=1M 页,因此需要 20 20 20 位才足够表示所有页面,又因为以字节作为编址单位,即页表项的大小至少为 3 B 3B 3B,一般会选择更大的页表项让一个页面能够正好容下整数个页表项,方便存储(如取成 4 B 4B 4B ,一页正好可以装下 1 K 1K 1K 个页表项)

地址变换过程

页表项是按顺序依次存放的,所以页号是隐含的,除去对应的物理块号外,页表项中还可能有一些控制位来实现存取控制,例如该物理块是只读的。

在这里插入图片描述

将逻辑地址分为页号和页内地址,以页号去检索页表,得到该页的物理块号,与页内地址拼接得到物理地址,此过程对用户完全透明,由硬件实现

在这里插入图片描述

存在问题

由于页表是存放在内存中的,这使 CPU 在每存取一个数据时,至少要两次访问内存,,为了解决这个问题,就出现了TLB


快表

为了解决页表需要多次访存的问题,在地址变换机构中增设一个具有并行查找能力的高速缓冲存储器——快表,又称相联存储器 TLB,用来存放当前访问的部分页表项,以加速地址变换的过程。

地址变换过程

将逻辑地址分为页号和页内地址,以页号去检索TLB,若TLB命中,则获得物理块号,若TLB未命中,则按上面基本的方式去检索页表,同时把页表项送入TLB(TLB和页表一般是同时进行查找的),若快表已满,则必须按照一定的算法对旧的页表项进行替换。

在这里插入图片描述

存在问题

TLB一定程度上解决了慢表多次访存的问题,但依然有新的问题,就是在虚拟存储器下,程序可以使用的逻辑地址往往非常大,页表也就会非常大,需要大片的连续空间,为了解决这个问题,就出现了多级页表


多级页表

对页表进行分组(地址分段),使得每个内存块刚好可以放入一个分组,并为离散的页表建立一张页目录表(外层页表,顶层页表)

各级单个页表的大小都不允许超过一个页面,一个页面放不下,就要分更多级的页表

建立多级页表的意义?

没有从根本上解决占据空间多的问题,事实上一个页表项都没有少,反而还多页目录表,但是建立多级页表的意义在于建立了索引,(因为进程的页表是常驻内存的,装入时建立,结束时销毁)就可以不用浪费主存空间去存储当前用不到的页表部分,并且实现了离散分配,无需大片连续空间

64位机下的多级页表

对于 64 64 64 位的计算机,如果要求它能支持 2 64 B ( 1844744 T B ) 2^{64}B(1844744TB) 264B1844744TB规模的物理存储空间,则即使是采用三级页表结构也是难以办到的;而在当前的实际应用中也无此必要。故在近两年推出的 64 64 64 位OS中,把可直接寻址的存储器空间减少为 45 45 45 位长度左右,这样便可利用三级页表结构来实现分页存储管理。

基本分段存储管理方式

分段存储管理方式的引入,带来以下边界

方便编程:用户可以把自己的作业按照逻辑关系划分为若干个段,每个段都是从 0 开始编址,并有自己的名字和长度

信息共享:在实现对程序和数据的共享时,是以信息的逻辑单位为基础的(比如函数,模块),而不是页面这种物理单位。

信息保护:信息保护同样是对信息的逻辑单位进行保护

动态增长:页面大小不可随意更改,段大小可更改

动态链接:动态链接要求以段作为管理的单位

逻辑地址结构

在这里插入图片描述

地址变换过程

段号也是隐藏的

image-20201223163439736 在这里插入图片描述

为什么说页式管理的地址是一维的,而段式管理是二维的?

页式存储各个模块在链接时必须组织在同一地址空间;而段式存储各个模块在链接时可以把每个段组织成一个地址空间。也就是说,在编程的时候,如果是分页存储,逻辑地址的页号和页内偏移量对用户是透明的,用户只需要给定一个虚拟地址,然后操作系统会自己去把虚拟地址划分成虚页号和页内偏移,所以是一维的。而如果是段式存储的话,段号和段内偏移量必须由用户显式提供,因为分段式从程序员的角度来分的,操作系统并不知道,所以段式存储是二维的(在高级程序设计语言中,这个工作由编译程序完成)

简单说就是,分页,程序员只需要给出一个虚拟地址,硬件会去计算页号和页内偏移量,所以是一维;而分段,程序员需要给出段号和段内偏移量,需要两个地址,所以是二维的。


分页与分段比较

目的

页是信息的物理单位。分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户是不可见的。

段是信息的逻辑单位。分段的主要目的是更好地满足用户需求。一个段通常包含着一组属于一个逻辑模块的信息。分段对用户是可见的,用户编程时需要显式地给出段名

大小

页的大小固定且由系统决定

段的长度却不固定,决定于用户编写的程序

地址空间

分页的用户进程地址空间是一维的,程序员只需给出一个记忆符即可表示一个地址。

分段的用户进程地址空间是二维的,程序员在标识一个地址时,因为段长不固定,所以既要给出段名,也要给出段内地址。

访存次数

页表和段表都是两次,第一次查表,第二次取数据(不考虑多级)

分段系统中也可以引入快表机构,将近期访问过的段表项放到快表

地址越界保护

先查段号是否越界,再查段内偏移是否越界

只需要判断页号是否越界,页内偏移不可能越界

段页式存储管理方式

综合分页分段的优点,用分段方法管理用户地址空间,用分页方法管理物理存储空间

三种“扩大”内存的方法

覆盖

早期的计算机内存很小,即便是单任务OS,主存中仅存放一道程序,存储空间放不下用户进程的现象也经常出现,于是出现了覆盖技术,只在早期OS中使用,已成为历史。打破了必须将一个程序的全部内容装入主存后才能运行的限制

基本思想

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

存在问题:

  • 当同时运行程序的代码量大于主存时仍不能运行
  • 对用户不透明,必须由程序员声明覆盖结构,增加了编程的负担

对换(交换)

多道程序环境下,把内存中暂时不能运行的进程(进程所需要的程序和数据)调出到外存上,以便腾出足够的内存空间,再把已具备运行条件的进程调入内存

进程对换与页面对换

进程对换是把整个进程换入换出(不包括PCB),页面对换是把进程的部分页面换入换出,两者都是交换技术,两者也并不矛盾,可以同时使用,例如:当系统缺页率很高时,可以换出一些进程。

进程对换,广泛应用于分时系统,用来解决内存紧张问题,并可进一步提高内存的利用率。

页面对换,是实现后面要讲到的请求分页和请求分段式存储管理的基础,其目的是为了支持虚拟存储系统。

对换区

为了更好的适应对换技术,磁盘分为文件区和对换区:

文件区,用于存放文件,由于通常的文件都是较长久地驻留在外存上,故对文件区管理的主要目标,是提高文件存储空间的利用率,为此,股对文件区采取离散分配方式。

对换区,用于存放从内存中换出的进程,作为磁盘的一部分,但是独立于文件系统,进程在对换区中驻留的时间是短暂的,对换操作又较频繁,故对对换区管理的主要目标, 是提高进程换入和换出的速度。故采取的是连续分配方式,不考虑外存中的碎片问题。

虚拟内存管理

虚拟存储器

具有请求调入功能和置换功能(对用户完全透明),能从逻辑上对内存容量加以扩充的一种存储器系统

局部性原理

程序在执行时将呈现出局部性规律,即在一较短的时间内,程序的执行仅局限于某个部分,称为时间局部性,因为程序中存在大量循环。相应地,它所访问的存储空间也局限于某个区域,称为空间局部性,因为指令通常是顺序执行的,并且存在数组、串等内存空间连续的数据结构。

传统存储器特征

  • 一次性,要求将一个作业全部装入内存后方能运行(多级页表只是允许用不到的二级页表不存在内存中)

  • 驻留性,作业被装入后,其全部部分就一直驻留在内存中(不考虑覆盖与对换,事实上,请求分页就是一种对换技术)

虚拟存储器特征

  • 多次性,与一次性相对,作业无需一次性全部装入
  • 对换性。与常驻性相对,作业无需全部数据一直常驻内存
  • 虚拟性,从逻辑上扩充内存的容量,虚拟性是以多次性和对换性为基础的

为什么要引入虚拟内存

多道程序并发执行不仅使进程之间共享了处理器,而且同时共享了主存,为了适应多道程序并发,需要更多的内存,但在物理上扩展内存是相对有限的,使用虚拟内存在逻辑上扩充内存

虚拟内存是怎么解决问题的?会带来什么问题?

使用外存上的空间来扩充内存空间,通过一定的换入/出策略,使得在逻辑上能够使用远超物理内存大小的内存容量

调换页面时需要访问外存,会导致平均访存时间增加,若使用了不合适的替换算法,驻留集大小分配不合适,反而会大大降低系统性能

虚拟内存(虚存)空间的大小由什么因素决定?

内存容量和外存容量之和,计算机的地址位数,二者共同约束

请求分页存储管理方式

硬件支持

页表机制(或段表机制),一般包含以下字段

  • 状态位 P:用于指示该页是否已调入内存
  • 访问字段 A:用于记录本页在一段时间内被访问的次数,供选择换出页面时参考
  • 修改位 M:表示该页在调入内存后是否被修改过
  • 外存地址:用于指出该页在外存上的地址,通常是物理块号,供调入该页时参考

缺页中断机构

缺页中断,属于内中断中的硬件中断,(与一般中断有区别,一般中断(外中断)是在指令执行结束后检查是否有中断信号)在指令执行期间产生和处理中断信号,但流程是一样的,同样要保存CPU现场,中断隐指令等。一条指令在执行期间,可能产生多次缺页中断

地址变换机构

请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,为实现虚拟内存又增加了某些功能而形成的。

在这里插入图片描述
页面置换算法

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

最佳置换 Optimal

选择以后永不使用的,或长时间不再被访问的页面淘汰,理想化的算法,具有最好的性能,但实际上无法实现


先进先出 FIFO

淘汰最先进入内存的页面,太公平,但是页面访问频率是不同的,有些页面经常被访问,比如,含有全局变量、常用函数、例程等的页面,FIFO 算法并不能保证这些页面不被淘汰,性能教差

Belady 异常
当分配物理块增多时,缺页次数反而增加,只有 FIFO 算法可能出现,就是因为太公平了,将先进入的频繁访问的页面置换了出去,导致出现此异常


最近最久未使用 LRU

选择最近最久未使用的页面予以淘汰,用一个访问字段来记录一个页面自上次被访问以来所经历的时间,需要专门的硬件支持(栈或寄存器),虽然性能好,但是实现困难,开销大


时钟置换 Clock

内存分配策略

驻留集大小

**工作集:**一段时间内访问的页面集合

**驻留集:**当前进程驻留在内存中的集合,就是系统给进程分配了多少内存块。

最小驻留集(指能保证进程正常运行所需的最小物理块数),驻留集太小时,进程会频繁缺页,系统花费大量时间处理缺页,驻留集太大时,进程几乎不缺页,那多道程序并发性就会降低,资源利用率低,一般来说,驻留集大小要大于工作集大小


分配策略

  • 固定分配:OS为进程分配一组固定数目的物理块,进行运行期间不再改变
  • 可变分配:OS先为进程分配一些物理块,在运行期间适当增加或减少

置换策略

  • 局部置换:发生缺页时只能选择进程自己的物理块进行置换
  • 全局置换:发生缺页时可以将OS保留的空闲物理块分配给进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页进程

固定分配局部置换

为每个进程分配一定数目的物理块,在整个运行期间都不改变,应为每个进程分配多少个物理块难以确定

可变分配全部置换

为系统中的每个进程分配一定数目的物理块,操作系统自身也保持一个空闲物理块队列。当某进程发生缺页时,系统从空闲物理块队列中取出一个物理块分配给该进程【只要缺页就给分配】,当空闲物理块用完时,OS 才会选择(可能是任何一个)进程的页面调出

最易于实现的一种物理块分配和置换策略

可变分配局部置换

为每个进程分配一定数目的物理块,当某个进程发生缺页时,只允许从该进程在内存的页面中选出一页换出,因此不会影响其他进程的运行。如果某个进程频繁缺页,OS 会为该进程多分配一些内存块;反之,如果进程缺页率特别低,会适当减少该进程的物理块【根据缺页率动态调整进程的物理块】

调页策略

调入页面的时机

预调页策略

根据局部性原理,一次调入若干个相邻的页,会比一次调入一页更高效

主要用于进程的首次调入,由程序员指出应该先调入哪些页

请求调页策略

进程在运行中需要访问的页面不在内存中而提出请求,由 OS 将页面调入内存

上面两种策略是一起使用的


从何处调入页面

当系统拥有足够的对换区空间时,全部从对换区调入所需页面

当系统缺少足够的对换区空间时,凡是不会被修改的文件(数据)都直接从文件区调入【就不需要写回了】,对于那些可能被修改的部分,在将它们换出时,便须调到对换区,以后需要时,再从对换区调入

UNIX 系统下,未运行过的页面,都从文件区调入,对于曾经运行过但又被换出的页面,被放在对换区,下次调入从对换区


请求调页过程

每当程序所要访问的页面未在内存时,便向 CPU 发出缺页中断,中断处理程序首先保留 CPU 环境,分析中断原因后转入缺页中断处理程序。该程序通过查找页表,得到该页在外存的物理块后, 如果此时内存能容纳新页, 则启动磁盘 I/O 将所缺之页调入内存,然后修改页表。如果内存已满,则须先按照某种置换算法从内存中选出一页准备换出;如果该页未被修改过,可不必将该页写回磁盘;但如果此页已被修改,则必须将它写回磁盘,然后再把所缺的页调入内存,并修改页表中的相应表项,置其存在位为“1” ,并将此页表项写入快表中。在缺页调入内存后,利用修改后的TLB,去形成所要访问数据的物理地址,再去访问内存数据。整个页面的调入过程对用户是透明的。(和Cache一样,调入之后,再从Cache中访问)


抖动

频繁发生缺页中断,刚刚换出的页面马上又要换入主存,刚刚换入的页面马上又要换出主存,这种频繁的页面调度行为称为抖动或颠簸

发生的原因:某个进程频繁访问的页面数目高于可用的物理块数目

有效措施:

  • 增大主存容量
  • 减少多道程序度数
  • 撤销部分进程

无用措施:

  • 使用更快速的CPU:抖动时CPU利用率不高

  • 增大磁盘交换区:抖动是换入换出频繁,但并不缺交换区容量

  • 更快速的磁盘交换区:换的越快抖的越厉害

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值