#pic_center
R 1 R_1 R1
R 2 R^2 R2
目录
- 知识框架
- No.1 内存的基础知识
- 一、什么是内存?有何作用?
- 二、内存单位
- 三、指令的工作原理
- 四、三种装入方式
- 1、绝对装入
- 2、可重定位装入
- 3、动态运行时装入
- 五、从写程序到程序运行
- 六、链接的三种方式
- 七、总结
- No.2 内存管理的概念
- 一、内存空间的分配与回收
- 二、内存空间的扩展
- 三、地址转换
- 四、内存保护
- 2、第二种内存保护
- 五、总结
- No.3 覆盖与交换
- 一、覆盖技术
- 二、交换技术
- 三、总结
- No.4 连续分配管理方式
- 一、单一连续分配
- 二、固定分区分配
- 三、动态分区分配
- 四、总结
- No.5 动态分区分配算法
- 一、首次适应算法
- 二、最佳适应算法
- 三、最坏适应算法
- 四、邻近适应算法
- 五、总结
- No.6 基本分页存储管理的基本概念
- 一、分页存储
- No.7 基本地址变换机构
- No.8 具有快表的地址变换机构
- No.9 两级页表
- No.10 基本分段存储管理方式
- No.11 段页式管理方式
- No.12 虚拟内存的基本概念
- No.13 请求分页管理方式
- No.14 页面置换算法
- No.15 页面分配策略
- No.16 内存映射文件
知识框架
No.1 内存的基础知识
各位同学大家好,从这个小节开始呢,我们会正式进入第三章,内存管理相关的知识点,那为了照顾到一些跨考的同学,我们会用这样的一个小节,来给大家介绍一下和内存相关的一些,啊基本的硬件常识,那在这个小节中,我们会简单的介绍一下什么是内存,内存有什么作用,然后会结合我们之前积累的那些知识,再进一步的更细化的理解,这个进程程序在CPU上是怎么运行的,我们会介绍一下指令的工作原理,并且介绍两个很重要的概念,逻辑地址和物理地址,那一个很重要的事情是,如何实现逻辑地址到物理地址的转换,那最后我们还会介绍啊,我们从写一个c语言程序,到最后程序运行,整个过程总共经历了哪些步骤,那我们会按照从上至下的顺序,依次讲解首先
一、什么是内存?有何作用?
今天我们来看一下什么是内存,内存有什么作用,其实内存这个东西,想必所有人都听说过接触过,比如说我们在买手机的时候啊,手机肯定有一个很重要的参数,就是内存,比如说这个啊什么华为P30,它是8 g b的内存,而后边这个64GB,这个其实指的是它外存的容量,那除了我们买手机的时候,可以看到手机的内存,我们买电脑的时候也会看到电脑啊,内存的大小,比如说呃像这个电脑就是32G,不过它的价格也是非常贵,不知道为什么可能自己有点膨胀,再来看一个稍微,便宜一点的,有的同学可能自己加装过内存条,所以可能在网上购买过一个单独的,内存条比如说这个就是4 g b这么大小,所以其实内存这个东西,我们或多或少肯定都听过,然后科班出身的同学,肯定也知道内存有什么作用,不过对于跨考的同学来说,也许内存是一个既熟悉又陌生的东西,其实内存它的作用就是用来存放数据,并且我们在之前的讲解当中提到过,程序在执行之前,需要先把相关的数据放入内存,才可以被CPU处理,那这么做的原因是因为,我们的程序本来是放在外存,放在词盘当中的,但是词盘的读写速度很慢,而CPU的处理速度又很快,所以如果CPU呃要执行这程序,程序相关的数据都是从外存读入的,那么很显然,CPU的这个速度,会被外存的速度给拖累,所以呃,为了缓和这个CPU,和硬盘外存之间的速度矛盾,所以我们必须先把呃我们要执行的,CPU要处理的这些程序数据,把它放到内存里,那接下来要思考的问题是这样的,既然我们的内存是存放数据的,那么我们的内存当中,可能会存放很多很多数据,那操作系统是怎么区分,各个程序的数据是放在什么地方的呢,那为了区分这些数据存放的位置,就需要给内存进行一个地址的编号,就有点类似于说我们去住酒店的时候,怎么区分我们每个人住在哪个房间,其实很,简单酒店的做法就是给每个房间,编号,比如说这是1号房间2号房间3号房间,等等等等,那我们的内存,其实和这个酒店是一样的,只不过酒店的这些房间里,你可以存的是人,而内存当中他的这些小房间里,他存的是一个一个的数据,那内存,会被划分成这样一个一个的小房间,每个小房间就是一个存储单元,那接下来在划分了这些存储单元之后,就需要给这些存储单元进行一个编号,那内存的这个地址编号,一般来说是从0开始的,然后依次递增,并且每一个地址会对应一个,数据的存储单元,也就是,只会对应一个小房间,那么这样的一个存储单元,可以存放多少数据呢,这个具体得看啊计算机的编制方式啊,我们在操作系统这门课当中,大部分遇到的情况是会告诉你说,计算机按字节编制,按字节编制的意思就是一个地址,它对应的是一个字节的数据,也就是说这样的一个存储单元,它可以存放一个字节,而一个字节它又由8个二进值为组成,也就是8个0101这样组成,那在有的题目当中,也有可能会告诉我们,这个计算机是按字编制的,如果他告诉我们是按字编制的话,那么就意味着一个地址,他所对应的存储单元可以存放一个字,而一个字的长度啊是多少个比特位,这个具体得看题目当中给出的条件,有的计算机当中字长是16位,那么它一个字的大小就是16个比特,也有的计算机可能字长是32位,字长是64位等等,总之我,们需要根据题目给的条件来判断,一个字它占有多少个比特位,好的那么在这个部分,我们为大家介绍了内存的一些,最基本的知识,什么叫做存储单元,就是用于存放啊数据的最小单元,另外每一个地址,可以对应这样的一个存储单元,而一个存储单元可以存储多少数据,那具体要看啊,这个计算机他是怎么设计的,对于我们考研来说,我们就要看他题目给的条件,到底是什么,那在内存管理这
二、内存单位
这个章节当中,可能会有很多题目会涉及到,这个数据的一些基本单位,而对于不考机组的同学来说,可能对这些单位的描述是比较陌生的,所以我们,在这个地方还需要再介绍一下一些,常见的单位,比如说我们平时所说的一个手机,或者说一台电脑,它有4GB内存,那除了GB之外,我们还经常看到什么MBKB这样的单位,那所谓的1K其实就是2的10次方这么多,而EM其实是2的20次方这么多,而这里的1G其实是2的30次方这么多,所以这个地方4G其实它是一个数量,而b是一个数据的单位,这个大b BYTE指的是字节,小b小写的b它指的是beat,是一个比特位,一个二进之位,一个BYTE也就是一个大币等于8个小币,所以如果一个手机有4GB内存的话,那么就意味着这个手机的内存当中,它可以存放4乘以啊2-30次方这么,多个字节的数据,所以如果这个手机或者这个电脑,它是按字节编制的,那么这个内存的地址空间就应该是,4乘以2的二三十次方,这么多个呃存储单元,每个存储单元可以存放一个字节,那我们知道在计算机的世界当中,所有的这些数字,其实都是用二进制0101这样来表示的,包括我们的内存地址,其实也需要用二进制来表示,所以有的题目当中可能会告诉我们呃,内存的大小是多少,比如说内存大小是4GB,并且告诉我们,这个内存是按字节编制的,题目可能会问我们,到底需要多少个二进制位,才能表示这么多个存储单元,也就是2的32次方格存储单元,那对于跨考的同学来说,一定要去了解一下二进制编码,还有二进制数,和这个十进制数的一个转换关系,对二进制比较熟悉的,就可以很快速的反映出来,这么多个呃存储单元,肯定就需要32个二进制位来表示,所以如果手机的内存是4GB,并且它是按字节编制的,那么对于这个手机来说,它的地址,至少需要用32个二进制位来表示,好的,那么再次提醒对于跨考的同学来说,如果二进制和十进制的这个转换啊,不是很熟练的话,一定要下去练习,好的那么再了解
三、指令的工作原理
内存的作用了解了内存的存储单元,内存的地址这些概念之后,我们再结合,之前我们提到过的一些基础啊,再给大家更进一步深入的,讲解一下指令工作的具体原理,这个知识点有助于大家对,后面的那些内容的啊更深入的理解,我们之前的学习当中提到过,其实我们用高级语言编程的代码,经过编译之后,会形成与他对应的等价的一系列的,机器语言指令,每一条指令就是让CPU,干一件具体的事情,比如说我们用c语言写的,x等于x加一,这样一个很简单的操作,经过编译之后,可能会形成这样的三条与他对等的,机器指令,那当这个程序运行的时候啊,系统会为他建立相应的进程,而我们之前学到过一个进程,在内存当中啊,会有一片区域叫做程序段,就是用于存放这个啊进程相关的那些,代码指令的,另外还有一个部分叫做数据段,数据段就是用来存放这个,程序所处理的一些变量啊之类的数据,比如说我们这儿的x变量,它就是存放在所谓的数据段里,那我们来看一下这三条指令分别,啊代表着什么呢,CPU在执行这几条指令的时候,首先它取出了指令一,然后指令一,它发现有这样的几个部分组成,第一个部分,红色的这个部分叫做操作码,就是指明了这条指令,是要干一件什么事情,这个地方的二金之码,我只是胡乱写的啊,大家只需要理解它的原理就可以了,那我们假设这个什么一零一1零零,它代表的是让CPU,做一个数据传送的事情,那后面的这两段数据,又是指明了这个操作相关的一些必,要的参数,比如说我们的指令一,就是让CPU从内存地址0100111,把这个地方存放的数据,把它取到对应实际制,就是编号为3的这个计存器当中,所以CPU在执行这个指令的时候,他会知道,我现在需要做的,事情是要做数据的传送,那怎么传送呢,我需要从地址为79的这个,嗯内存单元当中,把它里边的数据取出来,然后把它放到,编号为3的这个计算器当中,所以指令一的执行,就会导致,编号为3的这个计算器当中,有了10这个数,把x的值放到了这个计算器中,那在执行了指令一之后,CPU就会开始执行指令2,同样的他会解析这个指令,2到底是要干一件什么事情,根据他前面的这个部分,也就是所谓的操作码,他可以判断出啊,这个指令是要做一个加法操作,加法运算,而怎么加呢,CPU需要把编号为零一一,也就是换成时间制的话,就是,编号为3的这个计存器当中的内容,加上一所以根据这条指令,CPU会把这个计存器当中的值,从十加一,也就是变成11,那再接下来他要执行的是第三条指令,这个指令同样是一个数据传送的指令,可以看到,他的这个操作码,和第一个指令的操作码是一样的,就说明这两条指令,他们要干的是同一个事情,是同一种指令,只不过他们的参数是不一样的,大家可以对比着来看一下,那这个指令3,是让CPU干这样的一个事情,他需要把编,号为3的这个寄存器当中的内容,把它,写回编号为100111这个呃内存单元当中,所以CPU在执行第三条指令的时候,就会把这个寄存器当中的内容,把它写回x,这个变量,在内存当中存放的那个地址,因此这就完成了,x等于x加一这样的一个操作,当然刚才我们讲的这3条指令,只是我自己胡乱写的,其实并不严谨,如果大家想要了解啊,这些指令真正的什么操作码啊参数啊,到底是什么样一种规范,那还需要学习计算机组成原理,但是对于不考那门课的同学来说啊,只要理解到这一步就差不多了,总之从刚才我们讲的这个呃内容当中,我们可以很深刻的体会到,其实CPU在执行这些一条一条,指令的过程当中,它就是在处理这些内存啊,或者寄存器当中的一些数据,怎么处理这些数据,怎么找到这些数据呢,他就是基于,地址这一个很重要的概念来进行的,我们的内,存会有他自己的一些地址编制,同样的我们的寄存器也会有一些呃,他自己的地址编制,总之我们的程序经过编译之后,会形成一系列等价的机器指令,在这个机器指令当中,它会有一些相应的参数,告诉CPU你应该去哪些地址去读数据,或者往哪些地址写数据,那在刚才我们讲的这个例子当中,我们默认了啊我们所提到的这个进程,它是从0这个地址开始连续存放的,所以在他的这个指令当中是直接,指明了啊各个变量的存放位置,比如说啊x的存放地址,他就直接啊把他写死在了这个指令里,他是存放在,79这个地址所对应的存储单元里的,那接下来我们要思考的问题是这样的,如果我们的这个进程,他不是从0这个地址开始存放的,而是从别的地址开始存放的,会不会导致我们的这个,进程的运行出现一些问题呢,我们来具体看一下
大家的理解,在这个小节当中,我们都默认,操作系统给进程分配的是一片,连续的内存空间,那么,假设我们写了这样的一个c语言程序,嗯就是定义了一个变量x,x的值等于10,那这个c语言程序经过编译,链接等等一系列的处理之后,它会形成一个可执行文件,在Windows系统当中就是点exe,那这个可执行文件,又可以称作为装入模块,这个概念我们之后还会呃具体细聊,总之我们形成了这个装入模块,形成了这个可执行文件之后,就可以把这个可执行文件放入内存里,然后就开始执行这个程序了,不过需要注意的是,我们所形成的这个可执行文件,他的这些指令当中,所指明的这些地址参数,其实指的是一个逻辑地址,一个相对地址,所谓的相对地址就是指啊这个地址,指的是他相对于这个,晋城的起始地址而言的地址,有点绕不过其实并不难理解,在之前的那个例子当中我,们是默认了啊,这个晋城,他相关的这些数据,是从内存地址为,0这个地方开始存放的,所以这条指令,他是要进行x这个变量的初始化,并且他指明了x这个变量,他存放的地址是79,他的初始值为10,所以CPU在执行这条指令的时候,他会往79这个地址,所对应的内存单元里,写入x的初始值10,那这是我们刚才提到的情况,我们的这个程序装入模块,它是从内存地址为0这个地方开始,往后依次存放的,所以我们的指令当中指明的这些地址,并不会出现什么问题,那接下来再来看另一种情况,假设我们
我们的这个程序的装入模块,它装入内存的时候,并不是从地址为0的地方开始的,而是从地址为100的这个地方开始的,那么这就意味着操作系统给这个进程,给这个程序分配的地址空间,其实是100到279这么多,所以如果是这种情况的话,这个程序的这些呃逻辑地址,和它最终存放的物理地址,就会出现对应不上的情况,比如说我们的指令0,是要给x这个变量进行初始化,但是这个指令指明了x这个变量的值,它是要写到地址为79,的那个内存单元当中的,所以如果CPU执行这条指令的话,它就会把x的值10,把它写在上面的这个地方,79这个地址所对应的内存单元里,而这上面的这一片内存空间,极有可能是分配,给其他进程的,所以也就意味着,本来是这个进程他自己的数据,然而他强行往其他进程,呃的那个地址空间里去,去写入了自己的数据,那这显然是一个危险的,并且应该被阻止的一种行为,而事实上在这个例子当中,我们期待的x,这个变量的正确的存放位置,应该是从它的呃这个起始位置开始,往后79个单位这个的一个内存单元里,也就是179,这个地址所对应的内存单元当中,如果x的值写在这那就是没问题的,那讲到这,相信大家对逻辑地址和物理地址啊,应该有个比较直观的体会了,总之,我们的程序他编译链接等等之后,所形成的这些指令当中,一般来说使用的是逻辑地址,也就是相对地址,而这个程序,最终被装到内存的什么位置,这个其实是我们没办法确定的,所以在内存管理这个章节当中,有一个很重要的我们需要解决的问题,就是如何把这些指令当中,所指明的这些逻辑地址,把它转换为最终的啊,物理地址正确的物理地址,那这个小节当中,我们会介绍3种啊策略,来解决这个地址转换的问题,这三种策略分别是绝对装入,可重定位装入和动态运行时装入,那我们会依次来看一下,这三种策略是怎么解决这个问题的,首先来看第一种策略绝对装入所谓
四、三种装入方式
1、绝对装入
的绝对桩路就是指,如果我们能够在程序放入内存之前,就知道这个程序,会从哪个位置开始存放,那在这种情况下,我们其实就可以让编译程序,把各个变量存放的那些地址,直接把它,修改成一个正确的一个绝对地址,那还是以刚才的那个例子为例,比如说我们先前就已经知道了,我们的那个装入模块,它是要从地址为100的地方开始存放的,那么按照之前我们的介绍来说,这个装入模块,它里边,所使用到的这些地址都是相对地址,但是如果我们知道它是从100这个地址,啊开始装入的,那其实在编译的时候,就可以由编译器把它改为正确的地址,比如按照之前我们的分析,我们知道x那个变量,它正确的存放地址应该是179,所以接下来我们把这个装入模块,从起始地址为100的这个地方开始装入,那么当这个程序运行的时候,就可以把它的这些变量,存放到一个正确的位置了,所以这是第一种方式,在编译的那个时候,就把逻辑地址转换成最终的物理地址,但是有一个前提,就是我们需要知道我们的装入模块,它会装到内存的哪个位置,从什么地方开始装,所以这种方式的灵活性其实很差,它只适用于单道程序的环境,也就是早期的,还没有操作系统的那个阶段,呃使用的就是这样的一种方式,大家可以想一下,如果采用绝对装入这种方式的话,那么假设我的这个可执行文件,此时要运行在另外一台电脑当中,而另一台电脑当中,又不能让他从100这个位置开始存放,那么是不是就意味着这个程序,换一个电脑他就不能执行了,所以这种方式他的灵活性是特别低的,那接下来我们要学习
2、可重定位装入
第二种装入方式叫做可重定位装入,又叫静态重定位方式,如果采用这种方式的话,那么变异链接,最终形成的这个装入模块,这些指令当中使用的地址,依然是从0开始的逻辑地址,也就是相对地址,而把这些地址重定位这个过程,是留在了啊装入模块,装入内存的时候进行,比如说这个装入模块装到内存里之后,它的起始物理地址是100,那么如果我们采用的是静态,重定位这种方式的话,就意味着,在这个程序啊装入内存的时候,我们同,时还需要把这个程序当中所设计的,所有的这些和地址,相关的参数,都把它进行加100的操作,比如说令0我们就需要把它加一版,然后指令一也对,79这个内存单元进行了操作,所以这个地址我们也需要把它加一版,所以静态重定位这种方式,就是在我们的程序啊,装入内存的时候,再进行这个地址的转换,那这种方式的特点是,我们给这个作业分配的,这些地址空间必须是连续的,并且这个作业必须一次全部装入内存,也就是说在他执行之前,就必须给他分配,他所需要的全部的内存空间,那这可能同学们会奇怪,难道还可以只分配,他所需要的部分空间吗,那这个问题大家在学习了之后,的虚拟存储技术,之后就会有更深入的了解,并且这个地方其实也不是特别重要,那静态重定位这种方式,他还有一个特点,就是在这个呃程序运行期间,他是不可以移动的,这个很好理解,因为我们的这些指令当中已经,写死了,我们具体要操作的那个物理地址,到底是多少,如果这个程序,这个进程相关的这一系列的,数据发生了移动的话,那么这个地址的指向又会发生错误,所以这是静态,重定位这种方式的一个局限性,那最后我们
3、动态运行时装入
我们来看一下现代的系统,使用的这种地址转换的机制,叫做动态重定位又叫动态运行时装入,那如果采用的是这种方式的话,程序经过变异链接,最后形成的装入模块当中,它呃这些指令所使用的,其实也是逻辑地址,也就是相对地址,并且这个可执行文件,这个程序在装入内存的时候,他们的这个指令当中,所使用的同样还是逻辑地址,如果一个系统,支持这种动态重定位方式的话,那这个系统当中,还需要设置一个专门的一个,寄存器叫做重定位寄存器,从定位寄存器当中存放了这个进程,或者说这个作业,它在内存当中的起始地址是多少,比如说我们的这个程序,这个进程,它是从,起始地址为100的这个地方开始存放的,所以重定位寄存器当中,我们就存放它的起始地址100,而当CPU在执行,相应的这些指令的时候,比如说他在执行指令0的,时候这个指令0,是让他往地址为79的存储单元当中,写入x这个变量的初始值10,CPU在对一个内存地址进行访问的时候,他会做这样的事情,他把逻辑地址,和重定位寄存器当中存放的这个,起始地址,进行一个相加的操作,然后加出来的这个地址才是最终,他可以访问的地址,所以经过这样的一步处理,他就知道指令0是让他往,地址为179的这个地方写入数据 10,那很显然如果采用这种方式的话啊,我们想让进程的数据啊,在运行的过程当中发生移动,是很方便的,比如说我们啊把这个进程的数据啊,把它移到从200开始的话,那很简单,我们只需要把重定位寄存器的值,再修改成200就可以了,所以,动态重定位方式有很多很多的优点,它可以把程序分配到不连续的存储区,那不连续的分配这个现在先不展开,经过后续的学习,大家会有更深入的理解,这只是简单提一下,并且在程序运行的过程当中,只需要装入它部分的代码,就可以投入运行,而且可以在程序运行期间,根据需要动态的申请分配内存,便于程序段的共享,可以给用户提供一个比存储空间,大得多的地质空间,这些内容现在可能都看不懂,我们在学习了之后的虚拟存储管理,之后,就可以对这个特性有更深入的理解了,那这个地方我们也暂时不展开,把这个点的理解往后挪一挪,好的那么刚才
五、从写程序到程序运行
我们介绍了呃内存的基本知识,介绍了内存的地址,介绍了什么叫逻辑地址,什么叫物理地址,并且也介绍了3种装入方式,来解决了逻辑地址到物理地址的转换,这样的一个过程,那接下来我们再同一个更宏观,更全局的呃这样的一个角度,再来看一下,我们从写程序到程序运行,他所经历的步骤,首先程序员通过一些什么ID啊,或者一些甚至是一些文本编辑器啊,可以写出一些原代码文件,比如说像c语言里,我们的原代码文件就是点c文件,比如我们的这个原代码文件一例,我们定义了一个Mac函数,然后文件2例我们定义了一个a函数,文件3例定义了一个b函数,接下来经过编译之后,这些原代码文件,会形成若,干个与他们一一对应的目标模块,文件啊在c语言里就是点o文件,并且这些目标模块当中,其实已经包含了,这些代码所对应的那些,指令了而这些指令的编制都是呃,一个逻辑地址,也就是相对地址,每一个模块的编制都是从逻辑地址,0开始的,所以经过了编译之后,我们就把,高级语言,翻译成了与他们等价的机器语言,只不过在这,只不过,每一个模块的逻辑地址的编制,都是相互独立的,都是从0开始的,接下来的一步叫做链接,这一步做的事情就是把这些,目标模块都给组装起来,形成一个完整的装入模块,而在Windows电脑当中,所谓的装入模块,就是我们很熟悉的点exe文件,也就是可执行文件,把这些目标模块链接起来之后,所形成的装入模块,就有一个完整的逻辑地址,当然在链接这一步,除了我们自己编写的这些目标模块,需要链接以外,还需要把啊,他们所调用到的一些库函数,比如说printf啊之类的这些函数啊也给,链接起来,把它形成一个完整的装入模块,那有了装入模块,或者说有了这个可执行文件之后,我们就可以让这个程序开始运行了,那程序要运行所需要做的事情,就是我们刚才一直强调的那个过程,就是需要把这个装入模块,装入内存当中,并且当它装入内存之后,就确定了这个进程,它所对应的实际的物理地址,到底是多少,所以这就是我们从写程序,到程序运行的一个,完整的流程,那之前我们一直强调的是,装入这个步骤怎么完成,3种装入的策略,可以实现逻辑地址到物理地址的转换,那接下来我们要介绍的是,呃3种链接的方式,也就是这一步也有3种方法,第一种链接
六、链接的三种方式
方式叫做静态链接,就是指在程序运行之前,就把这些一个一个的目标模块,把它们链接成一个完整的克制性文件,也就是装入模块之后便不再拆开,就是我们刚才所提到的这种方式,也就是说在形成了这个装入模块之后,就确定了这个装入模块的完整的,逻辑地址,那第二种链接方式叫做,装入式动态链接,就说这些目标模块,不会先把它们链接起来,而是当这些目标模块,啊放入内存的时候,才会进行链接这个动作,也就说采用这种方式的话啊,这个进程的完整的逻辑地址,是一边装入一边形成的,那第三种方式叫做运行时动态链接,如果采用这种方式的话,那么呃,只有我们需要用到某一个模块的时候,才需要把这个模块丢入内存,比如说刚开始是main函数呃运行,那么我们呃,就需要把目标模块一先放到内存当中,然后执行的过程当中可能又发现,耐函数需要调用到a这个函数,所以我们需要把目标模块2,也把它放到内存当中,并且把它装入的时候同时,进行一个链接的工作,那如果说,b这个函数,在整个过程当中都用不到的话,那目标模块3我们就可以不装入内存,所以采用这种方式,很显然他的这个灵活性要更高,并且用这种方式,可以提升对内存的利用率,好的那么这个小节的内容
七、总结
比较杂比较多,但是又是的必须给,跨考的同学介绍的一些基础知识,我们首先介绍了什么是内存,内存有什么作用,介绍了内存的存储单元是什么,而一个存储单元可以存放多少数据,这个我们需要看这个呃,计算机,它到底是按字节编制还是按自编制,如果是按字节编制的话,那么一个存储单元就是存放一个字节,也就是一个大b一个,bite那内存地址,其实就是给这些存储单元的一个,编号,CPU可以根据内存地址这个参数来找到,正确的存储单元,那之后,我们就简单的介绍了指令工作的原理,一条机器指令,由操作码和一些参数组成,操作码给CPU,指明了你现在需要干的是什么事情,而参数指明了你现在需要怎么干,而这个参数当中可能会包含地址参数,而一般来说,这个指令中所包含的地址参数,指的都是逻辑地址,也就是相对地址,所以为了让这个指令正常的工作,我们就需要呃,完成,从逻辑地址到物理地址的一个转换,那为了完成,逻辑地址到物理地址的转换,我们又介绍了3种装入方式,分别是绝对装入,可重定位装入和动态运行时装入,其中,可重定位装入又称作为静态重定位,而动态运行时装入又称为动态重定位,这三种装入方式是考研当中比较,喜欢考察的内容,那最后我们还介绍了从我们,程序员写程序到最后的程序运行,需要经历哪些步骤,首先是要编辑原代码文件,然后原代码文件经过编译,形成若干的目标,模块,目标模块经过链接之后形成装入模块,最后再把装入模块装入到内存,这个程序就可以开始正常的运行了,那我们还介绍了3种链接的方式,分别是静态链接,装入式动态链接和运行式动态链接,其实经过刚才的讲解我们能够体会到,链接这一步就是要把,各个目标模块的那些逻辑地址把它,们组合起来形成一个完整的逻辑地址,所以链接这一步,其实就是,确定,这个完整的逻辑地址这样的一个步骤,而装入这一步,又是确定了最终的物理地址,那对于跨考同学来说,如果说有一些听不明白的地方,大家也可以放心大胆的往后学,这个小节的内容其实考察的频率很低,只不过是为了让大家更深入的理解,之后的内容,所以才进行了一些补充,好的以上就是这个小节的全部内容,
No.2 内存管理的概念
各位同学大家好,在这个小节中,我们会介绍内存管理相关的一些概念,其实就是来探讨一下,内存管理到底应该做一些什么事情,我们知道
一、内存空间的分配与回收
操作系统它作为系统资源的管理者,当然也需要对,系统当中的各种软硬件资源,进行管理,包括内存这种资源,那么操作系统在管理内存的时候,需要做一些什么事情呢,来看第一个问题,我们知道,各种进程想要投入运行的时候,需要先把,进程相关的一些数据放入到内存当中,就像这个样子,那么内存当中有的,区域是已经被分配出去的,而有的区域是还在空闲的,操作系统应该怎么管理这些空闲,或者非空闲的区域呢,另外,如果有一个新的进程想要投入运行,那么这个进程相关的数据,需要放入内存,当中但是,如果内存当中有很多个地方,都可以放入这个内存,这个进程相关的数据,那这个数据应该放在什么位置呢,这也是操作系统需要回答的问题,3如果说有一个进程运行结束了,那么,这个进程之前所占有的那些内存空间,应该怎么被回收呢,那所有的这些,都是操作系统需要负责的问题,因此内存管理的第一件事,就是要操作系统来,负责内存空间的分配与回收,那内存空间的分配与回收这个问题,比较庞大,现在暂时不展开细聊,呃之后还会有专门的小节进行介绍,那接下来再来看
二、内存空间的扩展
内存管理要实现了第二个功能,在第一个章节当中,我们提到过一个例子,在我的电脑当中,是可以运行一个叫做GTA的游戏,这个游戏大小超过60GB,但是我的电脑内存才有4GB,但理论上来说,这个游戏想要呃正常运行,想要被CPU处理的话,那么应该把这60G的,数据全部放到内存里,然而我的电脑内存才4GB,为什么这个游戏,还可以顺利的运行呢,其实这就采用了所谓的虚拟技术,这也是操作系统虚拟性的一个体现,那除了这个游戏之外,其实计算机当中也经常会遇到,实际的内存空间,啊不够所有的进程使用的问题,所以操作系统对内存进行管理,也需要提供某一种技术,从逻辑上对内存空间进行扩充,也就是实现所谓的虚拟性,把物理上很小的内存,拓展为逻辑上很大的内存,那这个问题也暂时不展开细聊,之后还会有专门的小节进行介绍,第3个
三、地址转换
需要实现的事情是地址转换,为了让编程人员编程更方便,程序员在写程序的时候,应该只需要关注指令数据的逻辑地址,而逻辑地址到物理地址转换,或者说地址重定位,这个过程应该由操作系统来负责进行,这样的话程序员就不需要再关心,层那些复杂的硬件细节,所以内存管理的第三个功能,就是应该实现地址转换,就是把程序当中使用的逻辑地址,把它转换成最终的物理地址,那么实现这个转换的方法,咱们在上个小节已经介绍过,就是用三种装入方式,分别是绝对装入,可重定位装入和动态运行时装入,绝对装入是在编译的时候,就产生了绝对地址,或者说在程序员写程序的时候,直接就写了绝对地址,这个这种装录方式,只在单道程序阶段才使用,但是单道程序阶段,其实暂时还没有产生啊,操作系统,所以这个地址转换,其实由编译器来完成的,而不是由操作系统来完成的,第二种方式叫做可重定位装入,或者叫静态重定位,就是指在装入的时候,把逻辑地址转换为物理地址,那这个转换的过程,是由装入程序负责进行的,那装入程序也是操作系统的一部分,那这种方法一般来说,是用于早,期的多道批处理操作系统当中,第三种装入方式叫做动态运行时装入,或者叫动态重定位,就是运行的时候才把,逻辑地址转换为物理地址,当然,这种转换方式一般来说需要一个硬件,重定位寄存器的支持,而这种方式,一般来说,就是现代操作系统采用的方式,咱们之后再学习夜市存储,还有段式存储的时候,会大量的接触,这种动态运行时装入的方式,所以说操作系统一般会用呃,可充电位装入,和动态运行时装入这两种方式,实现从逻辑地址到物理地址的转换,而采用绝对装入的那个时期,暂时还没有产生操作系统,那这就是内存管理需要实现的,第三个功能,地址转换,第四个功能叫
四、内存保护
内存保护,就是指操作系统,要保证,各个进程在各自存储空间内运行,互不干扰,我们直接用一个图,让大家更形象的理解,在内存当中,一般来说会分为操作系统,啊使用的内存序,还有普通的应用程,用户程序使用的内存序,那各个用户进程,都会被分配到各自的内存空间,比如说进程一使用的是这块内存区,进程2使用的是这块内存区,那如果说,进程一想对操作系统的内存空间,进行访问的话,很显然这个行为应该被阻止,如果进程一可以随意的更改,操作系统的数据,那么很明显会影响整个系统的安全,另外如果进城一想要访问其他进城的,存储空间的话,那么显然这个行为也应该被阻止,如果进城一可以随意的修改,进城2的数据的话,那么显然进城2的运行就会被影响,这样也会导致系统不安全,所以进城一,只能访问进城一自己的那个内存空间,所以这就是内存保护想要实现的事情,让各个进城,只能访问自己的内心内存空间,而不能访问操作系统的,也不能访问别的进城的空间,那我们假设,进程一的逻辑地址空间是0-179,实际的物理地址空间是100-279,也就是从100这个内存单元开始存储,那我们可以采用这样的方式来进行内,存保护,就在CPU当中设置一对上线寄存器,和下线寄存器,分别用来存储这个进程的内存空间的,上线和下线,那如果进程一的某一条指令,想要访问某一个内存单元的时候,CPU会根据指令当中,想要访问的那个内存地址,和上下限寄存器的这两个地址,进行对比,只有在这两个地址之间,才允许进程一访问,因为只有这两个地址之间的这个部分,才属于进程一的,啊内存空间,那这是第一种方法,可以设置一对上下限寄存器
2、第二种内存保护
第二种方法,我们可以采用重定位寄存器和,借地址寄存器,来判断此时是否有越界的嫌疑,那么,重定位寄存器又可以称为基址寄存器,借地址寄存器又称为现场寄存器,那重定位寄存器的概念,咱们在上个小节已经接触过,就是在动态运行时装入那种方式里,我们需要设置一个重定位寄存器,来记录每一个进程的起始物理地址,借地址寄存器又可以称为现场寄存器,就是用来存放,这个进程的最大逻辑长度的,比如说像进程一,它的逻辑地址空间是0到179,所以借地址寄存器当中,应该存放的是它的最大的逻辑地址,也就是179重定,而重定位寄存器的话,应该存放这个进程的起始物理地址,也就是100,那么假如现在进程一,想要访问逻辑地址为80的那个,呃内存单元的话,首先这个逻辑地址,会和借地址寄存器当中的这个值,进行一个对比,如果说没有超过界地址,寄存器当中保存的最大逻辑地址的话,那么我们就认为,这个逻辑地址是合法的,如果超过了那么会抛出一个月界异常,那没有月界的话,逻辑地址会和重定位寄存器的这个,起始物理地址进行一个相加,最终就可以得到,实际的想要访问的物理地址,也就是180,那这个
五、总结
小节中,我们学习了内存管理的整体框架,内存管理总共需要实现4个时期,内存空间的分配与回收,内存空间的扩充以实现虚拟性,另外还需要实现,逻辑地址到物理地址的转换,那么地址转换一般来说有3种方式,就是上个小节学习的内容,绝对装入,可重定位装入和动态运行式装入中,绝对装入这个阶段,其实是在早期的单道批处理阶段,才使用的,这个阶段暂时还没有操作系统产生,而可重定位装入,一般用于早期的多道批处理系统,现在的操作系统,大多使用的是动态运行式装入,另外呢,内存管理还需要提供存储保护的功能,就是要保证各个进程,他们只在自己的内存空间内运行,不会越界访问,那一般来说有两种方式,一种是设置以上下限寄存器,第二种方式是利用重定位寄存器和,借地址寄存器,进行判断,那么重订位寄存器又可以叫做,机址寄存器,而借地址寄存器,又可以叫做线长寄存器,这两个别名大家也需要注意,那么本章之后的内容,还会介绍更多的,内存空间的分配与回收,还有内存空间的扩充,啊的一些相关策略,那这个小节的内容不算特别重要,只是为了让大家,对内存管理到底需要做什么,形成一个大体的框架,好的,那么以上就是这个小节的全部内容
No.3 覆盖与交换
各位同学大家好,在这个小节中,我们会学习覆盖与交换,相关的一些知识点,那在之前的小节中我们已经学习到了,操作系统对内存进行管理,需要实现这样4个功能,那地址转换和存储保护是上个小节,详细介绍过的,那这个小节我们会介绍两种实现,呃内存空间的扩充的技术,覆盖技术和交换技术,那虚拟存储技术会在之后用更多的啊,专门的视频来进行讲解,那首先来看
一、覆盖技术
覆盖技术,在早期的计算机当中,内存一般来说是很小的,比如说IBM推出的第一台个人计算机,就只支持一兆字节大小的内存,那大家现在使用的这些程序,像什么QQ啊微信啊这些,可以自己去电脑上看一下,一般来说,都很少有低于100兆字节的这种程序,所以可想而知,一兆字节的大小,很多时候应该是,不能满足这些程序的运行的,那么后来人们为了解决这个问题,就引入了覆盖技术,就是解决,程序大小超过物理内存总和的问题,比如说,一个程序本来需要这么多的内存空间,但实际的内存大小又只有这么多,那怎么办呢,覆盖技术的思想就是要把,程序分成多个段,或者可以理解为就是多,个模块,然后常用的段就需要常驻内存,不常用的段需要呃,只有在需要的时候才需要调入内存,那内存当中会分一个,固定区和若干个覆盖区,常用的那些段需要放在固定区里,并且调入之后就不再调出,除非运行结束,这是固定区的特特征,那不常用的段就可以放在覆盖区里,只有需要的时候才需要调入内存,也就是调入内存的覆盖区,然后用不到的时候就可以调出内存,那我们来看一个具体的例子
假设有这样一个程序x,它有这样的一系列调用结构,就是呃a这个模块会依次调用b模块,和c模块,注意是依次调用,也就是说,b模块和c模块,只可能被a这个模块呃,在不同的时间段调用,不可能是同时访问b和c这两个模块,那同样的,b模块有可能会调入调用到d模块,然后c模块有可能会依次调,用到e模块和,f模块那么,如果我们的程序,是这样的调用结构的话,我们采用覆盖技术就可以,呃进行这样的设置,我们可以把包含MA函数的这个模块a,放到一个固定区里,那么这个固定区就是a,这个模块的大小,也就是8K,另外由于,b模块和c模块不可能同时被访问,也就是说在同一个时间段内,内存当中要么有b要么有c就可以了,不需要同时存在b和c这两个模块,所以我们可以让b和c,这两个模块共享一个覆盖区,那这个覆盖区的大小,呃以b和c这两个模块当中,更大的这个模块为准,也就是10K,因为如果我们把这个覆盖区设为10K,的话,那既可以存得下c也可以存得下b,那同样的,d e f这几个模块也不可能同时被使用,所以这几个模块也可以像上面一样,共享一个覆盖区,覆盖区一,那它的大小就是按他们之间最大的,这个也就是d模块的大小12K来计算,所以如果说我们的程序,有一个明显的这种调动结构的话,那么,我们可以根据他这种自身的逻辑结构,让这些不可能被同时访问的程序段,共享一个覆盖区,那只有呃,其中的某一个模块需要被使用的时候,那这个模块才需要放到覆盖区里,如果没有采用覆盖技术的话,那么这个程序要全部放入内存,需要8+8+10+12+4+10等于很多很多k,大家可以自己算一下,但是如果采用覆盖技术的话,我们只需要用10+8+12,也就是总共30K的大小,就可以让这个程序顺利的运行了,所以采用了覆盖技术之后,在逻辑上看,这个物理内存的大小是被拓展了的,不过这种技术也有一个很明显的缺点,因为这个程序当中的这些调用结构,其实操作系统肯定是不知道的,所以程序的这种调用结构,必须由程序员来显,性的声明,然后,操作系统会根据程序员声明的这种,呃调用结构,或者说覆盖结构来完成自动覆盖,所以,这种技术的缺点就是对用户不透明,增加了用户编程的负担,因此覆盖技术现在已经很少使用了,它一般就只用于早期的操作系统中,现在已经退出了历史的舞台,那接下来
二、交换技术
接下来我们再来看一下交换技术,交换技术,在有的地方又称作为兑换技术,他的设计思想是,当内存空间紧张的时候,系统可以把,内存当中的某些进程暂时换出外存,把外存当中已经具备运行条件的进程,换入内存,所以其实采用这种技术的时候,进程是在内存与磁盘,或者说外存之间动态的调度的,那之前咱们已经提过,其实已经提到过一个和交换技术,息息相关的知识点,咱们在第二章讲处理机调度的时候,讲过一个处理机调度层次的概念,分为高级调度中级调度和低级调度,那其中,中级调度就是为了实现交换技术,而使用的一种调度策略,就是说,本来我们的内存当中有很多进程,正在并发的运行,那如果某一个时刻,突然发现内存呃空间紧张,的时候,我们就可以把其中的某些进程,把它放到呃,暂时换出外存,而进程相关的PCB会保留在内,会插入到所谓的挂起对列里,那一直到之后内存空间不紧张了,内存空间充足的时候,又可以把这些进程,相关的数据再给换入,内存,那为什么进程的PCB需要常驻内存呢,因为进程被换出外存之后,其实我们必须要,通过某种方式记录下来,这个进程到底是放在外存的什么位置,那这个信息也就是呃进程的存放位置,这个信息,我们就可以把它,记录在与他对应的这些PCB当中,那操作系统就可以根据,PCB当中记录的这些信息,对这些进程进行管理了,所以进程的PCB是需要常驻内存的,那么中级调度或者说内存调度,其实就是在交换技术当中,选择一个处于外存的进程,把它换入内存这样一个过程,那讲到这个地方,大家也需要再回忆一下,低级调度和高级调度分别是什么,那既然提到了挂期,我们就,再来回忆一下和挂期相关的知识点
暂时换出外存等待的那些进程的状态,称之为挂启状态或者简称挂启态,那挂启态,又可以进一步细分为就绪挂启,和阻塞挂启两种状态,在引入了这两种状态之后,我们,就提出了一种叫做进程的7状态模型,那如果一个本来处于就绪态的进程,被换出了,外存那这个进程就处于就绪化其态,如果一个本来处于阻色态的进程,被换出外存的话,那么这个进程就处于阻色化其态,那其状态模型相关的知识点,咱们在第二章当中已经进行过补充,这就不再赘述,那大家可以再结合这个图回忆一下,这些状态之间的转换是怎么进行的,特别是中,间的这三个最基本的状态之间的转换,所以采用了交换技术之后,如果说,某一个时刻内存内的空间不够用了,那么我们可以把,内存当中的某一些进程数据,暂时换到外存里,再把某些更紧急的进程数据放回内存,所以,交换技术其实也在逻辑上拓充了呃,内存的空间,那么接下来
哎我们在思考三个问题,第一,我们把这些进程数据放到了外存,或者说词盘当中,那我们应该放到外存的什么位置呢,第二,我们应该在什么时候啊进行交换呢,第三我们在进行交换的时候,应该选择哪种进程把它换出呢,那先来看第一个问题,在现代计算机当中,外存一般来说就是磁盘,那具有兑换功能,或者说交换功能的操作系统当中,一般来说会把磁盘的存储空间,分为文件区和兑换区这样两个区,文件区主要是用来存放文件的,主要是需要追求啊存储空间的利用率,所以在对文件区,一般来说是采用离散分配的方式啊,这个地方一会再做解释,那兑换区的空间,一般来说只占此旁空间的很小的部分,注意被换出的进程数据,一般来说就是存放在兑换区当中的,而不是文件区,那由于兑换区的这个换入换出速度,会直接影响到,各个进程并发执行的这种速度,所以对于兑换区来说,我们应该首要追求换入换出的速度,因此,兑换区通常会采用连续分配的方式,那这个地方大家呃,理解不了咱没有关系,咱们在第4章文件管理的那个章节,会具体的在进一步学习什么是兑换区,什么是文件区,并且到时候大家就能够理解,为什么离散分配方式,可以更大的提高存储空间的利用率,而连续分配方式可以,提高换入换出的速度,这个地方他只需要理解一个结论,兑换区的IO速度,或者说输入输出的速度,是要比文件区更快的,所以我们的进程,数据被换出的时候一般是放在兑换区,换入的时候也是从兑换区再换回内存,那这就回答了我们的第一个问题,那再看第二个问题,我们在什么时候应该进行交换呢,一般来说,交换会发生在,系统当中有很多进程在运行,并且内存吃紧的时候,在这种时候,我们可以选择换出一些进程,来腾空啊内存空间,那一直到系统负荷明显降低的时候,就可以暂停换出,比如说,如果操作系统在某一段时间发现,许多进程运行的时候都经常发生缺液,那这就说明内存的空间不够用,所以这种时候,就可以选择换出一些进程,来腾空一些内存空间,那如果说缺液率明显下降,也就说看起来系统负荷明显降低了,我们就可以暂停换出进程了,那这个地方涉及到之后的小节会,讲到的缺液,还有缺液率这些相关的知识点啊,这理解不了没有关系,大家能够有个印象就可以了,第三个问题我们应该换出什么进程呢,啊这个地方我们给出一些参考的思路,首先我们,可以考虑优先换出一些阻塞的进程,因为处于就绪态的进程,其实是可以投入运行的,而处于阻塞态的进程,即使是在内存当中,反正他暂时也运行不了嘛,所以我们可以优先把阻塞进程,调出换到外存当中,第二我们可以考虑换出,优先级比较低的进程,那这个不用解释很好理解,第三如果我们每次都是,换出优先级更低的进程的话,那么就有可能导致优先级低的进程,刚被调入内存,很快又被换出的问题,那这就有可能会导致优先级低的进程,饥饿的现象,所以有的系统当中为了防止这种现象,会考虑啊进程在内存当中的驻留时间,如果的如果一个进程,在内存当中驻留的时间太短,那这个进程就暂时不会把它换出外存,那这地方再强调一点,PCB是会长度内存的并不会被换出外存,所以其实所谓的换出进程,并不是把进程相关的所有的数据,呃一个不漏的全部都掉到外存里,操作系统为了保持对这些换,出进程的管理,那PCB,这个信息还是需要放在内存当中,那么这就是交换技术
三、总结
小节我们学习了覆盖技术,和交换技术相关的知识点,那这两个知识点一般来说,只会在选择题当中进行考察,大家只要能够理解这两种,技术的思想就可以了,那么呃可能稍微需要记忆一点的就是,固定区和覆盖区相关的这些知识点,在固定区当中的程序段,在运行过程当中是不会被调出的,而在覆盖区当中的程序段在运行当中,在运行过程当中,是有可能会根据需要进行调入调出的,另外如果考察到覆盖技术的话,那么很有可能会把覆盖技术的缺点,作为其中的某一个选项进行考察,那在讲解交换技术的过程当中,我们补充了文件区和兑换区,相关的知识点,这些会在第4章中进行进一步的学习,那这地方大家只需要知道,换出的进程的数据,一般来说是放在词盘的兑换区当中的,那最后我们再来看一下,覆盖与交换这两种技术,的一个明显的区别,其实覆盖技术是在同一个程序或者,进程当中进行的,那通过之前咱们讲解的例子,这句话现在也不难理解,那相比之下,交换技术,是在不同进程或作业之间进行的啊,暂时运行不到的进程可以调出外存,那比较紧急的进程,可以优先被再重新放回内存,好的,那么以上就是这个小节的全部内容
No.4 连续分配管理方式
各位同学大家好,在这个小节中,我们会学习,连续分配管理方式相关的知识点,在之前的学习中,我们知道操作系统对内存进行管理,需要实现这样4个事情,那么内存空间的扩充,地质转换和存储保护,这是之前的小节介绍过的内容,从这个小节开始,我们会介绍,内存空间的分配与回收应该怎么实现,我们在这个小节中会先介绍,啊连续分配管理方式,分别是单一连续分配,固定分区分配和动态分区分配,我们会按从上至下的顺序依次讲解,那么这需要注意的是,所谓的连续分配,和非连续分配的区别在于,连续分配是指,系统为用户进程分配的,必须是一个连续的内存空间,而非连续分配管理方式是指啊,系统为用户分配的那些内存空间,不一定是连续的,可以是离散的,那么我们先来看单一连续分配方式
一、单一连续分配
采用单一连续分配方式的系统当中,会把内存分为一个系统区,和一个用户区,那系统区就是用于存放,操作系统相关的一些数据,用户区就是用于存放用户进程,或者说用户程序相关的一些数据,不过需要注意的是,采,用单一连续分配方式的这种系统当中,内存当中,同一时刻只能有一道用户程序,也就是说,他并不支持多道程序并发运行,所以用户程序是呃独占整个用户区的,不管这个用户区有多大,比如说一个用户进程或者说用户程序,他本来只需要这么大的内存空间,那当他放到呃内存的用户区之后,用户区当中其他这些空闲的区间,其实也不会被分配给别的呃用户程序,所以说是整个用户程序,独占整个用户区的这种存储空间的,所以这种方式其实优点很明显,就是实现起来很简单,并且没有外部碎片,那外部碎片这个概念,我们再讲到动态分区分配的时候,再补充这先,有个印象,那由于整个系统当中,同一时刻只会有一个用户程序在运行,所以啊,采用这种分配方式的系统当中,不一定需要采用内存保护啊,注意只是不一定,有的系统当中,它也会设置那种越界检查的一些机制,但是像早期的个个人操作系统,微软的DOS系统,就没有采用这种内存保护的机制,因为系统中只会运行一个用户程序,那么即使这个用户程序出问题了,那也也只会影响用户程序本身,或者说即使这个用户程序越界,把操作系统的数据损坏了,那这个数据一般来说,也可以通过重启计算机,就可以很方便的就进行修复,所以说,采用单一连续分配的系统当中,不一定采取内存保护,那这也是它的优点,那另一方面这种方式的缺点也很明显,就是只适用于单用户,单任务的操作系统,它并不支持多道程序并发运行,并且啊这种方式会产生内部碎片,那所谓的内部碎片,就是指我们分配给某一个进程,或者说程序的内存区间当中,如果有某一个部分没有被用上,那这就是所谓的内部碎片,像这个例子当中本来整个有,都是分配给这个用户进程a的,但是有这么大一块他是空闲的,暂时没有利用起来,那本来给这个进程分配了,但是这个进程没有用上的这一部分,内存区就是所谓的内部碎片,所以这种方式,也会遭导致存储器的利用率很低,那这是单一连续分配方式,那接下来
二、固定分区分配
大家来看固定分区分配方式,随着计算机的发展出现,慢慢的开始出现了多道程序技术,就是可以让各个程序啊同时装入内存,并且这些程序之间不能互相干扰,所以人们就想到了,把用户区划,分成了若干个固定大小的分区,并且在每一个分区内,只能装入一道作业,也就是说每一道作业,或者说每一道程序,他是独享,其中的某一个固定大小的分区的,那这样的话就,形形成了最早的,可以支持多道程序的内存管理方式,那固定分区分配可以分为两种,一种是分区大小相等,另外一种是分区大小不等,如果说,采用的是分区大小相等的策略的话,系统会把用户区的这一整片的内存区,间分割为若干个固定大小,并且大小相等的区,比如说每个区10兆自解像这样子,那如果说采用的是分区大小,不相等的这种策略的话,系统会把用户区分割为若干个,大小固定,但是大小又不相等的分区,比如说像这个样子,那这两种方式各有各的特点,如果说采用的是分区大小相等的,这种策略的话啊,很显然会缺乏灵活性,比如说一些小的进程,他可能只需要占用,很小的一部分内存空间,但是,由于每个每个分区只能装入一道作业,所以一个很小的进程又会,占用一个比较大的,很很多余的一个分区,那如果说一个有一个比较大的进程,进入的话,那么,如果这些分区的大小都不能满足这,个大进程的需求,那么,这个大进程就不能被装入这个系统,或者说只能采用覆盖技术,在逻辑上来拓展各个分区的大小,但这个显然又会增加一些系统开销,所以说分区大小相等的这种情况,是比较缺乏灵活性的,不过这,策略即使在现代,也是有很广泛的用途的,比如说啊,我们钢铁厂里有n个相同的炼钢炉,那么可以把内存,当中分为n个大小相同的区域,并且在这n个区域当中啊,放入n个一模一样的,炼钢炉的控制程序,由于这,n个炼钢炉本来就是相同的对象,所以,对这些相同的对象进行控制的程序,当然也是相同的程序,所以如果采用这种,把它分割为n个大小相等的区域,来分别存放n个控制程序,让这n个控制程序并发执行,并发的控制各个炼钢炉的话,那在这种场景下的应用就是很适合的,如果分区大小不等的话,呃灵活性会有所增加,比如说小的进程,我们可以给他分配一个小的分区,而大的进程,可以给他分配一个大的分区,那一般来说,可以先估计一下,系统当中会出现的大作业,小作业分别到底有多少,然后再根据大小作业的比例,来对这些分大小分区的,数量进行一个划分,比如说可以划分多个小分区,适量的中等分区,然后少量的大分区,那接下来我们再考
考虑下一个问题,操作系统应该怎么记,录内存当中各个分区的,空闲或者分配的这些情况呢,那一般来说,我们可以建立一个叫做,分区说明表的一个数据结构,用这个数据结构对各个分区进行管理,比如说,如果系统当中内存的情况是这个样子,那么我们可以给他,建立一个对应的分区说明表,那每个表象会对应其中的某一个分区,那每一个表象需要包含呃,当前这个分区的大小,还有这个分区的起始地址,然后这个分区是否已经被分配,的这种状态,那像这样一张表其实我们可以,建立一个数据结构,数据结构当中有这样一些属性,然后把这个数据,用这个数据结构组成一个数组,或者组组成一个列表,呃来表示这样一个表,那如果学过数据结构的同学,这应该不难理解,那操作系统根据这个数据结构,就可以知道各个分区的使用情况,如果说一个,用户程序想要装入内存的话,操作系统就可以来解锁这个表,然后找到一个大小能够满足,并且没有被分配出去的分区,然后把这个分区分配给用户程序之后,再把这个分区对应的状态,改成已分配的状态就可以了,那么固定分区分配,实现起来其实也不算复杂,并且,使用这种方式也不会产生外部碎片,那么外部碎片这个概念,咱们再往后拖一拖啊,下一个分配方式当中会进行讲解,但是这种方式也有很明显的缺点,如果说一个用户程序太大的啊,大到没有任何一个分区,可以直接满足它的大,小的话那么我们只能通过,覆盖技术来解决这个,分区大小不够的问题,但是如果采用了覆盖技术,那就意味着需要付出一定的代价,会降低整个系统的性能,另外这种分配方式,很显然也会产生内部碎片,比如说有一个用户程序啊,他所需要的内存空间是10兆,那么扫描了这个表之后会发现,只有分区6可以满足10兆这么大的需求,所以这个用户程序就会被分呃,就会被装到分区6里,但是,由于这个用户程序会独占整个分区6,所以分区6总共有12兆,那么就有两兆字节的,空间是呃分配了给这个程序,但这个程序又用不到的,那这一部分就是所谓的内部碎片,所以,固定分区分配是会产生内部碎片的,因此它的内存利用率也不是特别高,那么为了解决
三、动态分区分配
这个问题,人们又提出了动态分区分配的策略,动态分区分配,又可以称作可变分区分配,这种分配方式,并不会像之前固定分区分配那样,预先划分内存区域,而是在进程装入内存的时候,才会根据进程的大小动态的建立分区,而每一个分区的大小会正好适合,进程所需要的那个大小,所以和固定分区分配不同,如果采用动态分区分配的话,系统当中内存分区的大小和数目,是可以改变的,那我们来看一个例子,比如说,一个计算机的内存大小总共是64兆,啊字节然后系统区会占8兆字节,那用户区就是56兆,字节刚开始一个用户进程一到达,他总共占用了20兆字节的分区,之后一个用户进程2到达,占用了14兆字节的分区,用户进程3到达占用了18兆字节的分区,那么56兆的,用户区,总共只会剩4兆字节的空闲分区,那么系统中这些分区的大小和,数量是可变的,并且有些分区是已经被分出去的,有些分区又是没有被分出去的,操作系统应该用什么样的数据结构,来记录这个内存的使用情况呢,这是我们之后要探讨的第一个问题,那再来看第二个问题,如果此时占有14兆字节的进程2,已经运行结束了,并且被移出了内存,那么内存当中就会有,这样一片14兆字节的空闲区间,那此时如果有一个新进程到达,并且,这个进程需要4兆字节的内存空间,那这一片是这片空闲区间是14兆,这片空闲区间是4兆,那到底应该放这一片,还是放下面这一片呢,这又是第二个问题,当我们的内存当中有很多个空闲分区,都可以满足进程的需求的时候,应该,把哪个空闲分区分配给那个进程呢,这是第二个问题,第三个问题,假设此时占18兆字节的进程3运行结束,并且被撤离了内存,那么内存当中就会出现,18兆字节的一个新的空闲分区,那这个空闲分区应该怎么处理,是否应该和,他与他相邻的这些分区进行合并呢,这就是第三个问题,我们应该如何进行分区的分配,和回收的操作,那接下来我们依次对这三个问题,进行探讨先来看
第一个问题,操作系统应该用什么样的数据结构,记录内存的使用情况,那一般来说,会采用两种常用的数据结构,要么是空闲分区表,或者采用空闲分区列,比如某一个时刻,系统当中内存的使用情况是这个样子,总共有3个空闲分区,那么如果采用空闲分区表的话,这个表就会有3个对应的表象,每个表象会对应一个空闲分区,并且每个表象,都需要记录与这个表象,相对应的空闲分区的大小是多少,起始地址是多少等等一系列的信息,那如果说,没有在空闲分区表当中记录的那些,分区当然就是已经被分配出去的,再看第二种数据结构空闲分区列,如果采用这种方式的话,那么,每一个分区的起始部分和末尾部分,都会分别设置一个指向,前面一个空闲分区,和指向后面,指向后面一个空闲分区的指针,就像这个样子,所以就会把这些空闲分区,用一个类似于链表的方式,把它们链接起来,那么一个空闲分区的大小,还有空闲分区的起始地址呃,结尾地址等等这些信息,可以统一的把它们放在,各个空闲分区的起始部分,所以,这是我们可以采用的两种数据结构,空闲分区表和空闲分区链,那再来看第2个
问题当有很多空闲分区,都可以满足需求的时候,到底应该选择,哪个空闲分区进行分配呢,假如此时有一个进程5,他只需要4兆字节的空间,那么这个空闲分区,这个分区还有这个分区,这三个空闲分区,都可以满足他这个需求,那我们应该用哪个分区进行分配呢,那由这个问题,我们可以引出动态分区,分配算法相关的问题,那所谓的动态分区分配算法,就是要从,空闲分区表或者空闲分区链当中,按照某一种规则,选择出一个合适的分区,把它分配给啊,时请求的这个竞争或者说作业,那由于这个分配算法,这对系统性能造成的影响是很大的,所以,人们对这个问题进行了很多的研究,那这个问题我们现在暂时不展开处理,会在下一个小节进行详细的介绍,接下来我们再来看第三个问题,如何进行分区的分配与
有回收那假设我们采用的是,空闲分区表的这种数据结构的话,进行分配的时候,需要做一些什么操作呢,那这个地方我们只以空闲分区表为例,其实空闲分区链的操作也是大同小异,那假如说,此时系统当中有这样三块空闲的分区,如果此时有一个进程,需要申请4兆字节的,内存空间,那假设我们采用了某一种算法,最后决定从这20兆的空闲分区当中,摘出4兆,分配给这个进程物,就像这样,那么我们需要对这个空闲分区表,进行一定的处理,那由于这个空闲分区的大小,本来就是比,此次申请的这块,内存区域的大小要更大的,所以即使我们从这个分区当中啊,摘出一部分进行了分配,那么分区的数量依然是不会改变的,所以我们只需要在这个分区,对应的那个表象当中,修改一下它的分区大小,还有起始地址就可以了,那这是第一种情况,再来看第二种情况还是相同
例子有一个进程5需要4招字节,那如果说我们采用了某种分配算法,最后决定,把这4招字节的空闲分区,分配给这个进程5,那么本来这个空闲分区的大小,就和此次申请的这个内存空间大小,是相同的,所以如果把这个分区,空闲分区全部分配给啊这个,进程的话,那么显然空闲分区的数量会减一,所以我们需要把这个分区对应的,这个表象给删除,那如果说,我们采用的是空闲分区链的话,那我们就是需要把其中的某一个,空闲分区链的节点给删掉,那这是分配的时候,可能会遇到的两种情况,接下来我们,
我们再来看进行回收的时候,可能会需要做一些什么样的处理,假设此时系统内存中的情况是这样的,那如果采用空闲分区表,这种数据结构的话,那这个表应该是有两个表现,分别对应,一个10兆的空闲分区,和一个4兆的空闲分区,那假设此时进城4已经运行结束了,我们可以把进城4占用的这,4兆字节的空间给回收,那么此时,这块回收的区域的后面,有一个相邻的空间分区,也就10兆的这块分区,因此我们把这块内存分区回收之后,我们需要把,空闲分区表当中对应的那个,表象的分区大小和起始地址,也进行一个更新,所以可以看到,如果两个空闲分区相邻的话,那么我们需要把这两个空闲分区,进行合二为一的操作,再看第二种情况
假设此时进城3已经运行结束了,那么当进城3,占用的这一块分区被回收之后,在他的前面也有一个相邻的空间分区,所以参照刚才的那种思路,我们也需要把,这两块相邻的空间分区,进行合二为一的操作,那这和那这和之前的那种情况,其实很类似的
再看第三种情况,假设此时进城4已经运行结束,需要把这四招字节给回收,那么进城4的前面和后面,都会有一个相邻的空闲分区,所以,本来我们的空闲分区表有三个表象,也就是有3个空闲分区,但是当进城4的这块空间被回收之后,需要把这一整,块的空间都进行一个合并,所以本来系统中有3个空闲分区,但如果把进程4回收之后,就会合并为两个空闲分区,那当然,我们也需要修改相应表象的这些,分区大小,起始地址等等这一系列的信息,那这第三种情况需要把3,个相邻的空闲分区合并为一个,再看第四种情况
假如回收区的前后都没有相应的,空闲分区的话应该怎么处理,假设此时进程2已经运行结束,那么当进程2的这块,内存区间被回收之后,系统当中就出现了两块空闲分区,所以相应的,我们当然也需要增加一个,呃空闲分区表的表象,那通过刚才的这一系列讲解,大家可能会发现,我们对空前分区表的这种顺序,一般来说是采用这种呃,按照起始地址的先后顺序来进行排,列的,但是这个并不一定,各个表象的排序,我们一般来说,需要根据,我们采用哪种动态分区分配算法,来确定比如说,有的时候我们按照分区从大到小的,排列会比较方便,有的时候我们按照分区大小从小到大,进行排列会比较方便,当然也有的时候我们就像现在这样,按照起始地址的先后顺序来进行排列,会比较方便,那这个地方,会在下一个小节进行进一步的解释,那到这个地方,我们就回答了之前提出的三个问题,第一个问题,我们需要用什么样的数据结构来记录,内存的使用情况,一般来说会使用两种数据结构,空闲分区表或者空闲分区列,那第二个问题,涉及到动态分区分配算法,就会在下个小节中进行进步的解释,第三个问题,我们讨论了怎么对呃,内存的空间进行分配与回收,进行分配与回收的时候,需要对这些数据结构进行什么处理,那特别需要注意的是,在回收的过程中,我们有可能会遇到4种情况,不过本质上,我们可以用一句话来进行总结,在进行内存分区回收的时候,如果说回收了之后,发现有一些空闲分区是,相邻的那么我们就需要把这些,相邻的空闲分区全部给合并,那接下来我们再来讨论一下动态
分区分配,关于内部碎片和外部碎片的问题,这我们给出了内部碎片和外部,碎片的完整的定义,内部碎片是指,分配给某个进程的内存区域,当中如果说有些部分没有用上,那么这些部分就是所谓的内部碎片,注意是分配给这个进程,但是这个进程没有用上的那些部分,而Web碎片,是指内存当中的某些空闲分区,由于太小而难以利用,那因为各个进程,需要的都是一一整片连续的内存,区域,所以如果呃这些空闲的分区太小的话,那么任何一个,空闲分区都不能满足进程的需求,那这种空闲分区就是所谓的Web碎片,比如说,我们系统当中依次进入了进乘一,进乘2 进乘3,它们的大小分别是这样,然后这个时候,内存当中只剩下一片空闲的内存区域,就是4兆字节这么大,那么此时如果进程2暂时不能运行,我们可以暂时把它换出到外存当中,那于是这块就有14兆字节的空闲区域,那接下来进程4到达占用4兆字节,那这块就应该是10兆字节的大小,之后如果进城一也暂时不能运行,那么我们可以把进城一暂时换出外存,于是这个地方可以空出20兆字节的,连续的空闲区间,那接下来如,果进城2又可以恢复运行了,他在回到内存当中,他又占用了其中的14兆字节,于是这块就只剩下6兆字节,接下来如果说进程一也就20兆字节的,这个进程,又可以执行了,又想回到内存的话,那么此时会发现,内存当中的任何一个区,都已经不能满足,啊进程一的这个需求了,所以啊这就产生了所谓的外部碎片,这些空闲,区间,是暂时没有分配给任何一个进程的,但是由于他们都太小了太零碎了,所以没办法满足这种大进程的需求,那像这种情况下,其实内存当中总共剩余的空闲区间,应该是6+10+ 4,也就是总共有20兆字节,也就是说,内存当中的空闲区间的总和,其实应该是可以满足进程,于一的需求的,所以在这种情况下,我们可以采用紧凑技术,或者叫拼凑技术,来解决外部碎片的问题,那紧凑技术很简单,其实就是把各个进程挪位,把它们全部攒到一起,然后挪出一个更大的,空闲连续的空闲区间出来,这样的话,这块空闲,区间就可以满足进程仪的需求了,那这个地方大家也可以停下来,回忆一下,咱们刚才提到的换入换出技术,和终极调度相关的一些概念,这是咱们之前讲过的内容,那显然,咱们之前介绍的3种装入方式当中,动态重定位的方式其实是,最方便实现这些,程序或者说,进程在内存当中移动位置这件事情的,所以,我们采用的应该是动态重定位的方式,另外紧凑之后,我们需要把各个,进程的起始地址给修改掉,那进程的起始地址这个信息,一般来说,是存放在进程对应的PCB当中,当进程要上CPU运行之前,会把进程的起始地址,那个信息放到重定位寄存器里,或者叫寄址寄存器里,那大家对这些概念还有没有印象呢,那这个小节我们
四、总结
们介绍了3种连续分配管理的,分配方式,连续分配的特点就是,为用户进程,分配的必须是一个连续的内存空间,那么我们分别介绍了单一连续分配,固定分区分配,和动态分区分配这3种分配方式,那咱们之前留下了一个问题,单一连续分配和固定分区分配,都不会产生外部碎片,那由于采用这两种分配方式的情况下,不会出现那种暂时没有被分配出去,但是又由于这个呃,空闲区间太小,而没有办法利用的这种情况,所以这两种,分配方式是不会产生外部碎片的,那对于是否有外部碎片还是内部碎片,这个知识点,经常在选择题当中进行考察,大家千万不能死记硬背,一定要在理解了各种分配方式的,规则的这种情况下,能够自己分析到底有没有外部碎片,有没有内部碎片,另外动态分区分配方式当中,对外部碎片的处理紧凑技术,也是曾经作为,选择题的选项进行考察过,这个地方也需要有一些印象,那在动那在回收内存分区的时候,我们可能会遇到的这4种情况,也是曾经在真题当中考察过所,以这个点也需要啊注意,不过只需要抓住一个它的本质,相邻的空闲区间是需要合并的,我们只要知道这一点就可以了,另外呢我们也需要对,空闲分区表和空闲分区链,这两种数据结构,相关的概念,还有它们的原理要有一个印象,好的,那么以上就是这个小节的全部内容
No.5 动态分区分配算法
各位同学大家好,在这个小节中,我们会学习,动态分区分配算法相关的知识点,那这是我们上小节遗留下来的问题,在动态分区分配方式当中,如果有很多个空闲分区都能够满足,呃竞争的需求,那么,我们应该选择哪个分区进行分配呢,这是动态分区分配,算法需要解决的问题,在考试当中,要求我们掌握的有这样四种算法,首次适应最佳适应最快适应临近适应,这四种,我们会按从上至下的顺序依次讲解,首先来看
一、首次适应算法
首次适应算法,这种算法的思想很简单,就是每次从低地址部分开始查找,找到第一个能够满足大小的空闲分区,所以按照这种思想,我们可以把空闲分区,按照地址递增的次序进行排列,而每次分配内存的时候,我们就可以顺序的查找,空闲分区链或者空闲分区表,找到第一个能够,大小能够满足要求的空闲分区,进行分配,这个地方,提到了空闲分区链和空闲分区表,这是两种常用于表示,啊动态分区分配算法当中,内存分配情况的数据结构,那如果我们,此时系统当中内存的使用情况,是这样的,那采用空闲分区表的话,啊我们就可以得到一个这样的表,每一个空闲分区块,都会对应一个空闲分区表的表象,那这些,空闲分区块是按地址从低到高的顺序,一次进行排列的,那如果采用空闲分区链的话,其实也类似,也是按照地址从低到高的顺序,把这些空闲分区块依次的连接起来,那这个算法对这两种数据结构的操作,其实是很类似的,无非就是从头到尾依次检索,然后找到第一个能够满足要求的分区,所以这个地方,我们就以空闲分区链为例子,空闲分区表啊的操作其实也类似,那按照首次适应算法的规则,如果说此时有一个进程,要求15兆字节的空闲分区,那么我们会从空闲分区链的链头开始,依次查找,找到第一个能够满足大小的分区,那经过检查,发现第一个20兆字节的这个空闲分区,已经可以满足这个要求,所以我们会从,20兆字节的空闲分区当中,摘出15兆,分配给进程5,于是这个地方会剩于5兆字节的,空闲分区,那嗯相应的我们需要把,空闲分区链的对应节点的这些数据啊,包括分区的大小,还有分区的及时地址等等,这一系列的数据都进行修改,那么此时如果还有一个进程到来,他需要8照字节的内存空间,那我们依然还是会从空闲分区,链的链头,开始依次检索,那经过一系列的检索,会发现,第二个空闲分区的大小是足够的,于是我们会从第二个空闲分,区10兆字节当中,摘出8兆,分配给进城6,那这个地方会剩于两兆字节的空,闲分区所以我们和刚才一样,也需要修改空闲分区链当中相应的,分区大小,还有分区的起始地址这一系列的信息,那这个地方就不再掌课之述,所以这就是首次适应算法的一个规则,我们按照,空闲分区以地址递增的次序进行排列,并且每一次分配内存的时候,我们都会从链头开始依次往后寻找,找到第一个能够满足要求的空闲分区,进行分配,接下来来
二、最佳适应算法
看最佳适应算法,这种算法的思想其实也很好理解,由于动态分区分配算法是一种,连续分配的方式,那既然是连续分配,就意味着我们,系统为各个进程分配的空间,必须是连续的一整片区域,所以我们为了保证大进程到来的时候,有大片的连续空间可以供大进程使用,所以我们可以尝试,尽可能多的留下大片的空闲区间,那也就是说,我们可以优先的使用,更小的那些空闲区间,最佳适应算法会把空闲分区按照,容量递增的次序依次连接,那每次分配内存的时候会从头开始,依次查找空闲分区链或者空闲分区表,找到大小能够,满足要求的第一个空闲分区,那由于这个空,闲分区是按容量递增的次序,排序排列的,所以我们找到的第一个能够,满足的空闲分区一定是能够满足,但是大小又最小的空闲分区,那这样的话,我们就可以尽可能多的,留下大片的空闲,分区了,这个地方还是一样,我们就以空闲分区链作为例子,空闲分区表的操作其实也类似,如果说系统当中的内存,使用情况是这个样子,那么我们按照空闲分区块的大小,从小到大,也就是递增的次序链接的话,那应该是4020这样的顺序链接,如果说此时有一个新的进程到达,那这个进程,需要9兆字节的内存空间的话,按照最佳适应算法的规则,我们会从链头开始依次往后解锁,找到第一个能够满足要求的呃,空闲分区,也就10兆字节,于是我们会从从这10兆字节当中,摘出其中的9兆分配给这个进程,那这个地方就只剩下一兆字节的大小,但是由于最佳适应算法要求,我们空闲分区必须按照容量,递增的次序进行链接,所以啊这个地方变成了一兆之后,我们就需要对这个,整个空闲分区链进行重新排序,那最后会更新为这个样子,也就是把更小的这个空闲分区挪到,这个链的链头的位置,那之后,如果还有另外一个进程需要到达,他需要3兆字节的呃空闲分区的话,那同样的,我们也需要从链头开始依次查找,于是发现这个分区是可以满足的,那么第二个进程3兆字节,我们就可以从4兆当中找出3兆,给他分配,那这个地方也会,变成只有一兆字节的空闲分区,那我们之后就需要把这个,节点对应的那些空闲分区大小,空闲分区的起始地址,这些信息进行更新,那这个地方进行更新之后,整个空闲分区列,依然是按照容量低增的次序,进行链接的,所以我们就不需要再像刚才那样,进行重新排列,那这个地方就不再展开细聊了,那从刚才的这个例子当中,我们会发现,最佳适应算法有一个很明显的缺点,由于我们每一次选择的都是最小的,能够满足要求的空间分区进行分配,所以我们会留下越来越多,很小的很难以利用的内存块,比如说这个地方有一兆字节,这个地方又有一兆字节,那假如我们所有的进程,都是两兆字节以上,那这两个地方的,碎片就是我们难以利用的,所以采用这种算法的话,其实是会产生很多很多外部碎片的,那这是最佳适应算法的一个确定,那于是为了解决这个问题,人们又提出了最坏适应的算法,
三、最坏适应算法
他的算法思想和最佳适应刚好相仿,由于最佳适应,算法留下了太多难以利用的小碎片,所以我们可以考虑在每次分配的时候,优先使用最大的那些连续空闲区,这样的话我们进行分配之后,剩余的那些空闲区就不会太小,所以如果采用最快适应算法的话,我们可以把空闲分区按照容量,递减的次序,进行排列,而每一次分配内存的时候,就顺序的查找空闲分区链,找出大小能够,满足要求的第一个空闲分区,那由于这个地方,空闲分区是按,容量递减的次序进行排列的,所以啊,链头第一个位置的那个空闲分区,肯定是能够满足要求的,如果第一个都满足不了要求,那剩下的后面的那些空闲分区,肯定都比第一个空闲分区更小,那别的那些空闲分区肯定也不会满足,那还是来看一个具体的例子,假设此时系统,当中内存的使用情况是这样,那我们采用空闲分区表和空闲分区链,可以表示出此时的这些,空闲分区的情况,那按照最快适应算法的规则,我们需要按照容量递减的次序,依次把这些空闲分区进行排列,也就是2014,那此时假如有一个进程,他需要3兆大小的内存空间,那由于链,头的第一个空闲分区就可以满足,所以我们会从其中摘出3兆进行分配,那这个地方就变成了还剩17兆,那接下来如果还有一个进程也到达,他需要9兆内存,我们也是从这10念头的17照当中,摘出其中的9照分配给进程6,于是进行数据的更新,那更新了之后我们会发现,此时这个空闲分区链,已经不是按照容量递减的次序,进行排列的,所以我们需要把这个空闲分区链进行,重新排序,也就变成这个样子,十八四,依然保持按容量递减的次序进行链接,那如果有下一个进程到达的话,那我们第一个需要检查的就是10,这个空闲分区,那从这个例子当中可以看到,最坏适应算法确实解决了,刚才最大适应算法啊,留下了太多难以利用的,碎片的问题,但是,最坏适应算法又造成了一个新的问题,由于我们每次都是选择最大的分区,进行分配,所以这就会导致我们的那些大分区,会不断不断的被,分割为一个一个小分区,那如果之后有一个大进程到达的话,就没有连续的大分区可用了,比如说此时来了一个20兆的呃大进程,那这个大进程就无处安放,所以这是最化适应,算法的一个明显的缺点,那接下来我们再来看
四、邻近适应算法
看第四种临近适应算法,这种算法的思想其实为是为了解决,首次适应算法当中存在的一个问题,首次适应算法每次都会从链头,开始查找,这有可能会导致低地值部分出现很多,很小的难以利用的空闲分区,也就是碎片,但是由于呃首次适应算法又必须按照,地址,从低到高的次序来排列这些空间分区,所以我们在每次分配查找的时候,都需要经过呃低地址部分那些很小的,分区这样的话就有可能会增加,查找的一个开销,所以如果我们能够从,每次都从上一次查找,结束的位置开始往后解,解锁的话,是不是就可以解决,之前所说的这个问题了呢,所以临近适应算法其实和,呃首次适应算法很像,它也是把空间分区按照,地址地增的顺序进行排列,当然我们可以把它排成一个循环列表,这样的话比较方便我们解锁,那每一次分配内存的时候,都是从上次结束的位置开始往后查找,找,到大小能够满足的第一个空闲分区,那假如说此时,系统当中的内存使用情况是这样,那我们可以把这些空闲分区,按照地址递增的次序,依次进行排列,排成一个循环列表,刚开始如果说有一个进程到达,他需要5兆字节的内存空间啊,刚开始我们会从链头的位置开始,去查找,那第一个不满足第二个6兆是满足的,于是我们会从6兆当中,摘出5兆分配给他,那这个地方就还剩于一兆字节,于是我们需要更新这个呃,链当中对应的节点,包括分区的大小还有分区的其实地址,但是有没有发现啊,采用临近适应算法还有首次适应算法,我们只需要按照地址地之增的次序,进行排列,所以即使这个地方内存分区的大小,发生了一个,比较大的变化,但是我们依然不需要对整个列,表进行重新排列,所以这也是临近适应算法,还有首次适应算法,比最佳适应算法和,最坏适应算法更好的一个地方,算法的开销会比较小,不需要我们再花额外的时间对这个,列表进行重新排列,那假如此时有一个新的定程到达,他需要5兆字节的空间,那按照临近适应算法的规则,我们只需要从上一次,查找到的这个位置,依次再往后查找就可以了,所以这个不满足,那我们看下一个10兆是满足的,于是会从10兆当中摘出5兆进行分配,然后更新相应的这些数据结构,那这个地方大家有没有发现,如果此时我们采用的是首次试音,算法的话,如果此时需要分配5兆的内存空间,那么我们依然会从,练手的位置开始往后查找,所以第一个次兆不满足,第二个一兆不满足,第三个10兆才能满足,那这这会有三次查找,如果说我们采用的是临近,适应算法的话,我们只需要从这个位置开始往后查找,也就是查两次就可以了,所以这是临近适应算法比,首次适应算法更优秀的一个地方,首次适应算法会导致,低低值部分留下一些,比较小的碎片,但是我们每一次开始检索,都需要从,低低,值部分的这些小碎片开始往后检索,所以这就会导致,首次适应算法在查找的时候,可能会多花一些时间,不过这并不意味着临近适应算法就比,首次适应算法更优秀很多,其实,临近适应算法又造成了一个新的问题,在首次适应算法当中,我们每次都需要从第,地址部分的那些小分区开始,一次往后解,解锁但是这种规则也决定了,如果说在低地址部分有更小的分区,可以满足我们的需求的时候,我们就会,优先的使用低地址部分的那些小分区,这样的话就意味着,呃高地址部分的那些大分区,就有更大的可能性被保留下来,所以其实首次适应算法当中,也隐含了一点,呃最佳适应算法的优点,那如果我们采用的是临近适,应算法的话,由于我们,每次都是从上一次,检查的位置开始往后检查,所以我们无论是低地质部分,还是高地质部分的空闲分区,其实都是有相,同的概率被使用到的,所以这就导致了和首次适应算法相比,高地质部分的那些大分区,更有可能被使用,被划分成小分区,这样的话,高地质部分的那些大分区,也很有可能被我们用完,那之后如果有大进程到达的话,就没有那种,连续的空闲分区可以进行分配了,所以其实临近适应算法的这种策略,也隐含了一点最大适应算法的缺点,所以综合来看,其实刚才介绍的这4种算法当中,反而首次声音算法的效果是最好的,好的那么这个小节
五、总结
我们介绍了四种动态分区分配算法,分别是首次适应最佳适应,最快适应和临近适应,那这个小节的内容,很容易作为选择题进行考察,甚至有可能作为大题进行考察,其实我们只需要,理解各个算法的算法核心思想,就可以分析出呃,这些算法的这些,空闲分区应该怎么排列,他们的优点是什么,缺点是什么,那这几个算法当中,比较不容易理解的,其实是临近时算法的优点和缺点,但是刚才咱们也进行了详细的分析,这就不再重复了,那这个地方大家会发现,各个算法提到算法开销的大小问题,那这个地方的算法开销指的是,为了保证我们的空闲分区,呃是按照我们规定的这种次序排列的,在最佳适应和最坏适应这两种算法,当中我们,可能需要经常对整个空闲分区练,进行重新排序,所以这就导致了算法开销更大的,问题首次适应和邻近适应,我们并不需要对整个空前分区链进行,呃顺序的检查和排序,所以这个,这两种算法的开销是要更小的,那么这些算法,大家还需要通过课后习题的动手实践,来进行进一步的巩固,那么这就是这个小节的全部内容
No.6 基本分页存储管理的基本概念
各位同学大家好,在这个小节中,我们会学习一个很重要的高频考点,同时也是这门课的难点,叫做分页存储管理,那在之前的小节中,我们学习了几种,连续分配存储管理方式,所谓的连续分配就是指,操作系统给用户进程分配的是一片,连续的内存区域,而非连续分配就是指,他给用户进程分配的可以是一些,离散的不连续的内存区域,那这个小节我们会首先学习第一种啊,非连续的分配管理方式,叫做基本分页存储管理,那首先来认识
一、分页存储
试一下什么叫分页存储,如果一个系统支持分页存储的话,那么系统会把内存,分为一个一个大小相等的区域,比如说一个区域的大小是4KB,那这样的一个区域称为一个页框,或者叫一个页帧,当然他还有别的一些名词,不同的教材或者不同题目上,大家可能会看到啊,各种各样的名词出现,不过需要知道他们指的都是页框,那系统会给每个页框一个编号,并且这个编号是从0开始的,这个编号就叫,做页框号,或者叫页真号,内存快号物理快号物理页号,那接下来我们思考一下,内存里边,它存放的其实无非就是呃,各个进程的数据,对吧包括进程的代码啊,进程的呃指令啊等等这些数据,所以为了把各个进程的这些数据,把它呃放到各个页框当中,因此操作系统也会把,各个进程的这些逻辑递数空间,把它分为,与这个页,框大小相等的一个一个的部分,比如说我们这个地方举的例子进程a,它的逻辑递数空间是0-16 k减一,也就是16K,所以,这个进程的大小应该是16KB这么多,把它分为与页框,大小相等的一个一个部分,因此每个部分就是4KB这么多,并且系统也会给进程的各个页,啊进行一个编号,这个编号就称作为页号或者叫页面号,那进程的各个页会被放到,内存的各个页框当中,所以进程的页面和内存的页框,是有一一对应,一一映射的关系的,那这个地方建议大家暂停,好好的,来区分一下这几个很容易混淆的概念,特别是页页面页框和页帧这4个术语,在刚开始学习的时候,很容易认为他们指的是同一个东西,但其实不是,页框和页帧,他指的是内存,在物理上,被划分为的这样一个一个的部分,这个叫页框,而页和页面,指的是进程在,逻辑上被划分为的一个一个部分,那除了页框页帧之外,有的教材当中也会把,页框称为内存块,物理块或者叫物理页面,并且在我们的课后习题当中,这些名词都有可能出现,所以这个地方,建议大家特别注意一下这些,很容易混淆的概念,那到这,我们就初步了解了什么叫分页存储,接下来要思考的问题是这样的,刚才我们不是说进程的页面和,内存的这个页框,它有一一对应的关系吗,那操作系统是怎么记录,这种一一对应关系的呢,这就涉及到一
一个很重要的啊数据结构叫做页表,操作系统会给每一个进程都,建立一张页表,并且这个页表一般是存放在进,程的控制块当中的,也就是PCB当中,那刚才我们说过,进程的逻辑地址空间,会被分为一个一个的页面,那每一个页面就会对应,页表当中的一个页表项,所谓的页表项,大家可以理解为,就是这个页表当中的一行,那页表项当中包含了,页号和括号这样的两个数据,所以这样的一个页表,就可以记录下来这个进程的各个页面,和实际存放的啊,内存块之间的映射关系,注意内存块其实就是页框,只不过内存块这个术语可能啊,更不容易让人混淆一些,所以我们在接下来的讲解当中啊,更多的会使用的是,内存块这样的表述方式,不过大家自己答题的时候,建议使用页框这个术语,因为去看英文书的话,其实这个术语它的英文叫做page frame,所以大部分的教材,其实习惯翻译成页框,因此建议大家,答题的时候使用的是页框这个术语,好的那么再回到页,表这个数据结构啊,从刚才的分析当中我们知道,页表它由这样一个一个的页表像组成,那接下来我们要思考
的问题是这样的,首先这些页表像是存在内存里的,那每一个页表像,需要占几个字节的空间呢,第二个问题是,操作系统要怎么利用页表,来实现逻辑地址到物理地址的转换,那首先我们来分析第一个问题,直接结合一个例子来理解,假设我们的这个内存,它的大小是4GB这么多,并且每个页面的大小是4KB,那在这种情况下,我们的一个页表下,应该是多少个字节呢,首先我们来算一下这么大的内存区域,它会被分成几个页框,或者说会被分成几个内存块,那之前我们强调过,内存块的大小,或者说,页框的大小和页面的大小是相等的,所以一个内存块它就是4KB这么多,也就是2-12次方格字节,因此,4GB的内存总共会被分成2-20个次方,这么多个内存块,因为4 g b就是2的32次方个字节嘛,这种二进制的换算,大家一定要非常的快速熟练,那既然这个内存,会被分为这么多个内存块,因此要给这些内存块编号,那么它的快号的范围,就应该是0-2的20次方减一这么多,注意编号是从0开始的,而不是从一开始的,那如果要用二进制来表示,这个范围的地址,那就至少需要20个比特才可以表示,也就是说我们的页表项当中,快号这个参数,它至少需要占用20个比特,不过呢计算机分配存储空间,它是以字节为单位分配,而不是以比特为单位分配,所以20个比特,它至少要用3个字节来存储,因此一个页表项当中,快号这个属性至少需要占用3个字节,那注意刚才我们分析的这个思路,我们通过内存块的数量,推算出了啊,页表项当中快号至少要占多少个字节,那这个是考试当中经常考察的一个点,那接下来我们再来看一下,这个页号又需要占多少个字节呢
直接告诉大家答案,页号是不需要占存储空间的,因为各个页表像在内存中连续存放,所以页号可以是隐藏的,什么意思呢,那刚才我们得出的结果是,一个快号他至少需要占用3个字节,并且这些页表像,在内存当中都是连续存放的,那如果在内存中只存储快号,而而没有存储页号的话,那我们又怎么找到,页号为i的这个页面对应的页表像呢,其实很简单,只要我们知道了这个页表,它在内存当中存放的起始地址x,我们就可以用x加上3乘以i,就得出这个i号页表像它的存放地址,那学过数据结构的线性表,相信这个地方并不难理解,其实就相当于是一个数组,对于普通的数组而言,数组的下标,我们也不需要花呃存储空间来存放,对吧因此我们得出结论,页表当中的这个页号可以是隐藏的,它并不占用存储空间,那结合之前的结论我们知道,一个页表像,它在逻辑上,其实是包含了业号和快号,这样的两个信息,但是在物理上,它其实只需要存放快号这个信息,只有快号需要占用存储空间,那如果这个进程它的页号是0到n号,也就是说它总共有n加一个页面的话,那么存储这个进程的页表,就至少需要3乘以n加一这么多个字节,那我们通过页表可以知道各个页面,它存放在哪个内存块当中,但是需要注意需要强调的是,这个地方它记录的只是内存的快号,而不是具体的内存块的起始地址,如果我们要计算,一个内存块的起始地址的话,我们需要用这个快号再乘以,内存块的大小,这个地方大家需要特别的注意,体会一下,不然做题的时候很容易出错,好的,那么到这我们就弄清楚了第一个问题,接下来要探索
好的是第二个问题,如何实现地址的转换,也就是逻辑地址转换到物理地址,那我们先来回忆一下,我们之前在讲,连续存放那种方式的时候,操作系统是怎么实现,这种地址的转换的呢,如果一个进程他在内存当中连续存放,那么我们只需要知道这个进程,他的起始地址,然后把接下来要访问的那个逻辑地址,和起始地址相加,就可以得到他最终的物理地址,那这是连续存放的时候,那这个逻辑地址,我们可以把它理解为是一种偏移量,也就是说相对于他,的起始地址而言往后偏移了多少,那如果采用分页存储的话,那这个地址转
话要怎么进行呢,这个进程,会被放到内存的各个位置当中,不过有这样的一个特点,虽然进程的各个页面,在内存中是离散的存放的,但是各个页面的内部它都是连续的,注意体会这个特点,那基于这个特点我们来看一下,如果要访问逻辑地址a,应该怎么来进行呢,首先我们可以确定这个逻辑地址a,它啊应该对应的是进程的哪个页面,也就是说要确定这个逻辑地址a,它所对应的页号,接下来操作系统就可以用这个页号,去查询页表,然后找到这个页面,它存放在内存当中的什么位置,那第三步我们要确定的是逻辑地址a,它相对于这个页面的起始位置而言,的偏移量是多少,因为各个页面内部都是连续存放的嘛,所以我们只需要把这个呃逻辑地址a,它所对应的页面,在内存当中的起始地址,再加上这个逻辑地址的页内偏移两w,就可以得到这个逻辑地址a,所对应的物理地址了,那这个就是实现地址变换的一个,基本的思路,那在之前的讲解当中,我们啊了解了怎么利用页表,来找到一个页面在内存,当中的起始地址,那接下来我们要探讨的就是啊,怎么确定逻辑地址所对应的页号,和页内篇一量,还是结合一个
例子来理解,假设一个系统当中,啊每个页面的大小是50个字节啊,某个进程,它的逻辑地址空间大小是200个字节,那我们来看一下,对于这个进程来说,逻辑地址110,它所对应的啊,页号和页面的偏移量分别是多少呢,那很显然这个进程会被分为4个页面,编号分别是0-3,那0号页面的起始地址是零,一号页面起始地址是50啊,以此类推,那很显然,110这个逻辑地址他应该是在2号页面,并且相对于2号页面的起始地址而言,他的页内偏移量应该是10,所以,其实我们可以用这样的方式来计算,页号等于逻辑地址除以页面长度,取除法的整数部分,那可以试一下110除以页面大小50,等于整整数部分就是2,所以他所对应的页号是2号页,那页内偏移量呢,我们可以用逻辑地址对页面的长度啊,页面大小进行一个取余,取它的余数部分,所以110啊对50取余应该是10,因此,这个逻辑地址的页内偏移量应该是10,所以用这样的计算方式,我们可以把逻辑地址,拆分成这样的两个部分,分别是页号和页内偏移量,那只要知道逻辑地址对应的页号,就可以用页号来查询页表,然后就可以知道,页表在内存当中的起始地址,接下来再用这个起始地址,加上页内偏移量,就可以得到最后的物理地址了,那在这个例子当中,一个页面大小是50个字节,但其实在线,实生活中,由于计算机内部它是用二进制来表,示所有的东西的,包括地址也是用二进制来表示的,所以如果把页面的大小设置为啊,刚好是2的整数次密这么大的话,那么计算机硬件啊,把逻辑地址,拆分为页号和页内偏移量的速度,就会快很多,我们来看一下为什么啊,假设一个计算机,它是用32个二进之位来表示逻辑地址,每个页面的大小刚好是2的整数次密,也就是2:12次方格字节,也就是说,一个页面应该是409六个字节这么多,那0号页面的逻辑地址范围,应该是0到4095这么多,如果用二进值表示的话,应该是这个样子啊,黑色的部分大家可以数一下,应该是有12个二进值位,从全0到全一,而红色部分啊都是全0,1号页面的逻辑地址应该是这个范围,如果用二进制表示的话,末尾的这12位呃也是从全0到全一,而2号页面的逻辑地址范围,用二进制表示的话,也有同样的规律,红色部分如果转换成十进制的话,会发现红色部分刚好是2,所以有没有发现,如果页面的大小,是2点12次方格字节这么多的话,那么末尾的这12位,其实就是页内偏一亮,而前边的这20位红色的部分,其实表示的就是业号,可以再找几个例子试一下,逻辑地址2如果用二进值表示的话,应该是这一位是一,然后别的全是0,那我们用上一页PPT,当中介绍的那种算法啊,页号,等于这个逻辑地址除以页面的大小,可以算出页号是0,而页内篇一量用刚才所介绍,的取余的这种操作,算出来页内篇应该是2,再来一个例子,逻辑地址4096,如果用二进纸表示的话,应该是这个样子,那用之前介绍的除法和取余,这两种算法,算出来的结果,其实和我们之前得到的结论是一样的,啊页号其实就是前边的这20位,所表示的数字,而页内偏移量就是后边的这12位,所表示的数字,当然需要把它转化成10静值,那熟悉二进制乘法或者无符号左移,无符号右移这些啊操作的同学,可能很容易理解这个原理,但是对于跨考同学来说,也许会觉得他比较神奇,但不知道为什么会这样,那如果想要了解,呈现这种规律背后的原理的话,建议啊可以去看一下无符号左移,无符号右移和二进制的乘法,二进制的除法之间的一个联系,好的扯远了,回到我们的这个主题上来啊,总之通过刚才例子我们可以体会到,如果每个页面是2的整数,次密啊这么大的话,那么啊二进制的末尾,k位就可以表示页的偏移量,其余部分就是页号,计算机硬件不需要再,做这种复杂的除法或者取余的操作,他只需要直接取前面几位作为页号,后边几位作为,啊这个页内偏移量就可以了,所以这个特性,可以让计算机硬件,更快速的把逻辑地址,拆分成页号和页内偏移量,这样两个部分,那除此之外他还有另外一个优点
我们继续沿着刚才的例子来看一下,就是逻辑地址4097,我们得到它的页号啊是这么表示,然后页内偏移量是这么表示,那假设这个计算机中,物理地址,也是用32个二进之位来表示的话,那么 0号内存块的起始物理地址,应该是这个样子,1号内存块,起始物理地址应该是这个样子,2号3号 以此类推,不难发现,红色部分的二进制,转换成十进制数之后,和他的这个快号其实刚好也是相等的,那还记得我们刚才讲页表的时候,强调过一个问题吗,页表当中记录的是内存快号,而不是内存快的起始地址,所以如果我们要计算一个,内存快的起始地址的话,需要进行一个这样的乘法运算,但是,如果内存快的大小刚好是2的整数,密呃计算起来就没有那么麻烦,我们假设1号页面,它存放的内存快号是9,如果用二进值表示的话,9这个数就应该是1001,那如果用我们之前介绍的,这种土办法来计算的话,我们可以知道,9号内存快它的起始地址应该是9,乘以啊内存快大小4096,那这个乘法的结果,如果转换成二进值数就是这个样子,大家可以自己动手试一下,可以看到,用这种土办法算出来的结果当中,红色的这个部分啊,前面的这20位其实也是1001,所以这个逻辑地址4097,他所对应的物理地址就应该是,他在内存当中的起始地址,再加上他的页内偏移量,那在内存中的即使地址是这一串,它的页内偏移量又是这一串,所以把它们俩相,加刚好就是把后面的这黑色的这一串,把它替换成了页内偏移量这一串,那这么完美的特性,其实就是因为页面大小,内存块的大小刚好是2点整数次密,所以在地址转换的过程当中,我们只要查到,页表当中存放的这个内存快号,再把这个内存快号和,逻辑地址的页内篇一量进行一个拼接,其实就可以得到最终的物理地址了,如果不是2点整数次密的话,页面在内存中的及时地址,必须用这样的乘法的方式来进行,这也会导致硬件的效率降低,那经过刚才的这两个例子
我们可以看到呃,页面大小是2的整数字密,有这样的两个好处,这个地方大家再结合文字,好好体会一下就可以了,就不再重复,那如果页面大小是2的整数次密的话,我们可以把逻辑地址,把它分为这样的两个部分,分别是页号和页内偏移量,那如果有k位表示页内偏移量的话,就说明这个系统当中,一个页面的大小是2的k次方格,内存单元,如果有m位表示页号的话,那么就说明在这个系统当中,一个进程,最多允许拥有2的m次方格页面,总之呢只要知道页内偏移量的位数,就可以推出页面大小,同样的知道页面大小,也可以反推出页内偏移量应该占,多少位,从而就可以确定逻辑地址的结构,这一点也是考题当中,非常非常高频的一个考点,大家在做题的时候会经常,遇到当然有的题目当中,它的页面大小有可能不是2的整数词,密那对于这种题目来说,我们要计算页号和页内偏移量,还是只能用最原始的那种算法,呃用除法来得到页号,用取域得到页内偏移量,好的那么这个小节中我们
我们介绍基本分页存储管理的,呃一些知识,系统会把进程分页,会把各个页面,离散的放到各个内存块当中,或者说放到各个页框当中,那初学者很容易混淆的是这些概念,大家一定要注意,在做题的时候,所有的这些名字都有可能出现,那由于各个页面会,依次放到各个内存块当中,所以需要记录,这种页面和内存块之间的映射关系,因此需要有一个很重要的书结构,叫做页表,页表由一个一个的页表相组成,并且页表相在内存中是连续存放的,各个页表相大小相等,注意页号是隐藏的,不需要占用存储空间,那我们只需要知道,页表在内存当中存放的起始地址,并且知道页号和页表相的大小,就可以算出,i号页表相存放在什么位置了,那最后我们还介绍了,分页存储的逻辑地址结构,可以分为页号和页内偏移量,这样两个部分,如果页面大小刚好是2的整数次密,那么硬件在拆分呃逻辑地址,在进行物理地址的计算的时候都会,都会更快,所以一般来说,呃页面大小都是2的整数次密,当然,这个小节中我们还介绍了在分页存储,这种管理方式当中,怎么实现逻辑地址到物理地址的转换,具体的转换过程,大家现在只需要,有个大体的印象就可以,下个小节当中我们还会结合,一些硬件的细节,再进一步的阐述一直转换的过程,好的,那么以上就是这个小节的全部内容
No.7 基本地址变换机构
各位同学大家好,在这个小节中,我们会学习基本地址变换机构,相关的内容,那这个小节内容,也属于基本分页存储管理,其实所谓的基本地址变换机构,就是在基本分页存储管理当中,用于实现逻辑地址,物理地址转换的一组硬件机构,那我们在学习这个小节的过程当中,需要掌重点掌握,啊这些变换机构的工作原理,还有流程,这个小节的内容十分重要啊,极有可能作为选择题,也有可能结合大题进行考察,那通过上个小
直接的讲解,我们知道在分页存储管理当中,如果要把逻辑地址,转换成物理地址的话,总共需要做4件事,第一要知道呃逻辑地址对应的页号,第二还需要知道,逻辑地址对应的页内偏移量,第三,我们需要知道逻辑地址对应的页面,在内存当中存放的呃位置到底是多少,第四我们再根据呃,这个页面,在内存当中的起始位置和页内偏移量,就可以得到最终的物理地址了,那为了实现这个地址转换的功能,系统当中会设置一个页表寄存器,用来存放页表在内存当中,的起始地址还有页表的长度,这两个信息,在进程没有上处理机运行的时候,页表的起始地址,还有页表长度这两个信息,是放在进程控制快里的,只有当进程被调度,需要上处理机的时候,操作系统内核才会把这两个数据,放到页表寄存器当中,那我们接下来用一个动画的形式,看一下,从逻辑地址到物理地址的转换,应该是什么样一个过程,我们知道,操作系统,会把内存分为系统区和用户区,那在系统,就当中会存放着一些呃,操作系统对,整个计算,机软硬件进行管理的一些相关的数据,结构包括进程控制快PCB,也是存放在系统区当中的,那如果说一个进程被调度,他需要上处理机运行的话,进程切换相关的那些内核程序,就会把呃这个进程的运行环境给恢复,那这些进程运行环境相关的信息,本来是保存在PCB当中的,之后啊这个内核程序会把这些信息,把它放到相应的一系列寄存器当中,包括页表寄存器,页表寄存器当中存放着,这个进程的页表的起始地址,还有页表的长度,另外呢,像程序计数器PC也是需要恢复的,程序计数器是指向,这个进程下一条需要执行的,指令的逻辑地址,逻辑地址a,那么接下来我们来看一下,怎么把这个逻辑地址,转换成实际的物理地址,也就是说,CPU怎么在内存当中找到,接下来要执行的这一条指令那,从上个小节的讲解中我们知道,采用分页存储管理方式的,这种系统当中,逻辑地址结构肯定是固定不变的,在一个逻辑地址当中页号有多少位,页内偏移量有多少位,这些啊操作系统都是知道的,所以只要知道了逻辑地址a,那么就可以很快的呃切分出,页号和页内偏移量这样的两个部分,接下来,会对页号的合法性进行一个检查,一个进程的页表长度m,指的是这个进程的页表当中,有m个页表象,也就意味着这个进程的页面总共有,m页所以如果此时想要访问的页号,已经超出了这个进程的页面数量的话,那么就会认为此时,想要访问的这个逻辑地址是非法的,这样就需要抛出一个越界中段,那如果说这个页号是合法的,那么接下来会用这个页号和页表食指,来进行计算,找到这个页号对应的,页表项到底是多少,那通过上个小节的讲解我们知道,页表当中的每一个页表项的长度,其实是相同的,所以其实只要我们知道了页号,还有页表起始地址,在知道我们每一个页表项的长度,我们就可以算出我们想要访问的页号,对应的页表项所存放的位置,那既然知道了他存放的内存快号,我们就可以在,用内存快号结合页内偏移量,得到最终的物理地址,然后就可以顺利的访问,逻辑地址a所对应的那个内存单元了,所以整个过程做了这样几件事,第一是根据逻辑地址算出了,页号和页内偏移量,第二需要检查这个页号是否越界,是否合法,第三如果这个页号是合法的,那么我们会根据页号还有页表食指来,计算出这个页号对应的页表,项应该是在什么地方,然后找到相应的页表项,第四在,我们得知了,这个页面存放的内存快号之后,我们就可以,用内存快号还有页内篇一量,来计算出最终的物理地址,然后最后再对这个物理地址进行访问,那在考试当中,经常会给出一个逻辑地址还有页表,然后让我们计算对应的物理地址,所以大家需要对上面所说的这些过程,都非常的熟悉,那接下来我们再
用文字的方式再给出一个描述,虽然说这个呃内容比较重复,但是也是因为这个部分的内容极其,重要所以想呃多让大家过几遍,那如果说一个系统当中页面大小是l,我们,变化需要经过这样几个步骤,第一我们需要,用逻辑地址a,计算页好p还有页内偏移量w,如果说题目当中是用实金制给出的话,我们啊对页号和页内偏移量的计算,分别是这个样子,这个在上个小节当中也介绍过,但是对于计算机来说实际运行的时候,逻辑地址结构是固定不变的,因此计算,机硬件就可以根据这个逻辑地址结构,很快速的得到啊,2,用二进制表示的页号和页内偏移量了,在得到了页号和页内偏移量之后,我们需要对页号啊进,行一个合法性的检查,就是用页号和页表长度m进行个对比,如果页号大于等于m的话,那就会发生一个越界中断,否则就会继续执行,这个地方需要注意的是,当叶号p等于叶表长度m的时候,也会发生越界中断,因为叶号是从0开始的,而叶表长度至少是1,所以假如一个进程的页表长度是一,那么他的页号最大只应该是0,如果想要访问页号为一的那个页面,那其实就应该已经发生越界了,所以这个地方去等号的时候,也是会产生越界中断的,那这个小细节一定需要注意,那在确认页号合法之后,我们就需要呃在页表当中,找出这个页号对应的页表像地址,那页表像地址就等于页表的起始地址,f再加上页号p乘以页表像的长度,那这个式子的由来,咱们在上小节当中也介绍过,那在找到了,这个页号对应的页表像之后,就可以取出页表像里的内容b,也就是这个页面存放的内存快号,那对于初学者来说,这有几个很容易混淆的概念,页表像长度,页表长度还有页面大小这三个概念,所谓的页表长度,指的是这个页表当中,能够有几个页表像,那一个进程的页表当中有几个页表像,就意味着这个进程总共有几个页面,而页表像长度,指的是每个页表像,应该占多大的存储空间,那页面大小呢,指的是每一个页面应该占,多大的存储空间,那这几个概念确实是比较容,易混淆的特别是页表长度,还有页表像长度这两个概念一定要呃,着重注意一下,那在我们知道了这个,呃页面存放的物理块号之后,我们就可以呃用,物理快号乘以页面的长度l,再加上页内偏一两w,就可以得到最终的物理地址了,不过这种计算方式,一般是我们,手动做题的时候使用的一种方式,对于计算机来说,其实想要得到物理地址,有一种更简单的方法,其实计算机只需要把内存快号b,还有页面偏一两w,用二进值表示,再把这两个二进值数拼接起来,其实就是最终的物理地址了,那这个地方,大家可以自己动手验证一下,假设一个系统当中页面大小l是1KB,也就是2的10次方格字节,那最终要访问的内存括号是b等于2,页内偏一量w等于1023,那么大家可以分别尝试用这种方式,还有刚才提到的把,内存快号和页内篇一量,用二进制表示,并且把它们拼接起来,得到物理地址的这种方式,来看一下这两种结果是否一致,那这个地方呢,验证这就暂时不展开,大家下去动手尝试一下那
我们用一个具体的题目来练练手,假设一个系统当中,页面大小l为1K字节,也就是2的10次方字节,页号2对应的内存快号b等于8,也就是2号,页面应该存在内存快号为8的地方,将逻辑地址a等于2,500转换成物,理地址1,这个题目其实还有一些等价的问法,比如说某系统按字节寻址,按字节寻址就意味着这个系统当中,每个地址对应的是一个字节,逻辑地址结构中页内拼音量占10位,这个信息很重要,页内偏移量的位数,其实,直接就决定了一个页面的大小是多少,那么偏移量占10位的话,就说明一个页,面的大小应该是2的10次方的字节,也就是1KB,所以这种说法和上面这种说法,其实是等价的,在做题的时候,一定要注意这个页内偏移量,还有页面大小之间的这种,应关系那进行地址的转换,第一步我们应该呃,根据这个条件算出页号和页内偏移量,由于题目当中给出的是这种,实径制表示的逻辑地址,所以我们用,除法还有区域操作这样的方式来计算,会更方便一些,经过计算发现页号是2页内篇译量是452,而根据题目当中给出的条件,页号2对应的呃内存快号等于8,也就是说明,页号为2的页表像是存在的,因此页号2肯定没有越界,并且查询页表之后,已经知道,这个页面应该是存放在内存快号,为8的地方,那第三步我们知道了内存快号,知道了页号页内偏移量,我们就可以计算物理地址,物理地址等于啊,这个内存快号乘以每个页面的大小,或者说每一个内存块的大小,再加上页内偏移量,那最终就可以得到8644这样一个结果,大家有没有发现,其实在分页存储管理或者说夜市管理,的系统当中,只要我们,确定了每个页面的大小是多少,那么逻辑历史的结构,肯定就已经确定了,所以夜市管理当中的地址是一维的,我们并不需要告诉系统,除了逻辑地址以外的别的信息,不需要显示的告诉他啊,页面偏移量占多少啊,页号占多少,因为这些信息都是确定的,所以在夜市管理当中,我们想要让系统,把逻辑地址转换成物理地址,需要告诉系统一个信息,也就是逻辑地址的值,不需要再告诉系统别的任何信息,那因为只需要告诉他一个信息,因此这个地址是一维的,那这就是我们手动的模拟,基本地址变换,机构啊,转换地址的一个过程,很多初学者会忽略的是,对业号进行越界检查的这一步操作,所以这个地方需要留个心眼,那接下来我们再对
上一节提到过的页表像大小,这个问题进行进一步的探讨,在上个小节中,我们已经知道,每个页表像的长度是相同的,页号是隐含的,那如果一个系统当中内存大小4 g b,页面大小4 k b,那这些内存总共会被分为,2-20次方格内存框,所以我们至少需要用20个二进之位,才能表示这么多的内存框号,所以,页表像的长度至少要3个字节才够,那这些页表像,会被连续的存放在内存当中,并且每个页表像的长度都是这样,三个字节,所以只要我们知道了呃,这个页表在内存当中存放的起始地,址x就可以用x加上3乘以m,得到m号页面,对应的呃页表像存放的位置,但是,我们再把这个问题深入的分析一下,这个系统当中一个页面大小是4 k b,所以每个页面可以存放呃4096除以3,也就是1365个页表像,但是1365个页表像并不能占满整个页框,这个页框,还会剩余一个字节的页内碎片,那由于这个地方只剩一个字节的,空闲区域了,所以下个页表像只能存放在,下一个页框当中,它不能跨页框的存储,所以1365号页表像存放的地址,应该是x加上3乘以1365,再加一加一,就是为了,消除这剩余的一一字节造成的误差,所以可以发现,如果说我们的这些页表像,并不能装满整个页框的话,那在查找页表像的时候,其实是会造成一些麻烦的,所以为了解决这个问题,我们可以把每个页表像的长度再,拓展一下,把它拓展到四个字节,这样的话,我们就可以保证每个页框,刚好可以存放整数个102四个页表像,并且不会有任何的这种页内碎片,就像这个样子,这样的话我们要查询1024号的页表像,我们就不需要像上面这么麻烦了,因为,这个页框当中不会有任何的页内碎片,所以在理论上来说,页表像的长度,最短3个字节就可以表示,所有的这些内存括号的范围,但实际用当中为了啊方便页表的查询,经常会让一个页表像占更多的,字节使得每个页面,恰好可以装得下整数个页表像,不过即使这个页表像长度是3个字节,其实也没问题,只不过在,查询页表的时候,可能会需要做一些更麻烦的处理,如果在题目当中,要要我们算,页表像的长度最小应该是多少,那我们按照,3字节这样的思路来处理就可以了,4个字节啊,这样的处理只是实际应用当中,为了方便而采用的一种策略,那经过刚才的这个例子,大家有没有发现一个进程,如果他的页表太大,也就是页表项太多的话,那么,这个进程的页表一般来说装到内存里,也是会尽可能的让他装在,连续的一些内存块当中,因为这样的话,我们都可以用统一的一个呃计算方式,就可以得到,我们想要得到的那个页表项,所存储的位置,好的那么在这
小学当中,我们学习了如何使用,基本地址变换机构,这一系列的硬件,来实现地址转换的一个过程,那基本地址变换机构当中,最重要的硬件就是页表寄存器,大家需要知道页表寄存器有什么作用,这个小节中,最重要的是要掌握,地质变换的整个过程,我们要知道,计算机是怎么使一步一步实现这些地,质变换的,并且还要能用手动的方式啊,手算的方式,来模拟出整个地质变换的过程,那这部分是大题和小题的,极高频的出题点,除了地址变换过程之外,我们在讲解的过程中,也补充了一些小的细,节比如说,页内偏移量的位数和页面大小之间,是有一个对应关系的,那如果说,题目当中给出了页内偏移量的位数,大家需要能够推出页面的大小,同样的如果告知我们页面大小,也能要能够推出页内偏移量的位数,如果知道地址逻辑地址的总位数的话,那么我们还要能够写出,整个逻辑地址的地址结构,这个小知识点,在计算题当中是很容易用到的,那除了这个之外,夜市管理的地址是一维的,这一点也经常在选择题当中进行考察,那大家要理解什么叫一维,所谓的一维就是说我们要让呃,CPU帮我们找到某一个,逻辑地址对应的物理地址的话,我们只需要告诉CPU一个信息,也就是逻辑地址的值,并不需要再告诉他其他的任何信息,所以这是一维的含义,而另外的这两个小细节,只是为了,能够让大家更充分的了解这种,夜市管理的这种机制才补充的,但考试当中呃一般来说不会考察,那除了这些内容之外,我们还需要注意一个很重要的知识点,在CPU得到一个,呃想要访问的逻辑地址之后,一直到呃实际,访问了这个逻辑地址对应的内存单元,的整个过程当中,总共需要进行两次访问内存的操作,第一次访问内存是在查询页表的时候,进行的第二次访问内存,是在实际,访问目标内存单元的时候进行的,那在下个小节当中,我们会探讨一种新的地址变换机构,是否能用一种别的地址变换机,构来减少访问内存的次数,从而加快整个地址变化,还有访问的过程呢,那这是下个小节想要探讨的问题,好的,那么以上就是这个小节的全部内容
No.8 具有快表的地址变换机构
各位同学大家好,在这个小节中,我们会学习具有快表的地址变换机构,那上个小节中我们学了,基本地址变换机构,还有,逻辑地址到物理地址转换的一个过程,那在基本地址变换机构的基础上,如果引入了快表的话,就可以让这个地址变换的过程更快,所以这个小节中,我们首先会介绍什么是快表啊,并且会介绍引入了快表之后,一直变化的过程有什么区别,最后我们会解释为什么引入快表之后,可以让计算机的整体效率,整体性能都得到啊很高的提升,那首先来看一下什么是快
快表又称为联想寄存器英文缩写是TRB,它是一种访问速度比内存快很多的,高速缓存,注意TRB它不是内存,它是一种高速缓存,那快表中,存放的是最近我们访问过的一些页表,像的副本,这样的设计可以让地址变换速度更快,那具体的我们一会儿会用,更详细的例子来帮助大家理解这句话,那像之前我们学习的那些小节当中,我们都知道,页表其实是存放在内存当中的,在引入了快表之后,我们可以把,存放在内存中的页表称为慢表,因为访,问内存中的这个页表的速度更慢,而访问快表当中,存放的这些页表项的速度会更快,所以这是快表和慢表名字的由来,那下面我们来简单的介绍一下,什么是高速缓存,其实在我们的计算机当中,计算机中的这些存储设备,这些存储用的硬件它是分层级的,最便宜的啊,存储设备一般来说就是硬盘,或者叫自盘,现在电脑一般硬盘都是1TB或者两tb,之类的,但是由于硬盘的读写速度很慢,而CPU处理数据的速度又很快,因此CPU不可能直接,每一次想要哪一个数据,都从硬盘当中读取,那这样肯定会因为硬盘速度慢,而拖累啊CPU的速度,导致系统整体性能降低,所以一般来说CPU要处理的那些数据,都会先从硬盘读入内存当中,内存的速度要比硬盘快好几十倍,所以我们把CPU要访问的那些数据,先放到内存中,就可以缓和,CPU和硬盘之间的速度矛盾,但是虽然内存的速度已经很快了,然而,CPU处理数据的速度还是要快很多,因此又设计了高速缓存这种东西,就是把内存当中,最近有可能会被频繁访问到的东西,可以先把它放到高速缓存里,然后CPU可以先访问高速缓存,如果高速缓存当中,已经找到自己想要的数据,那么就不必再去访问内存了,这样的话,又可以进一步的缓和,CPU和存储设备之间的一个速度矛盾,所以其实高速缓存,它本质上也是用于存取数据,的一个应急设备,只不过它的速度要比内存快很多,可以更好的配合高速的CPU的工作,但是需要再次强调的是,缓存并不是内存,CPU访问高速缓存的速度,要比访问内存的速度要快得多,因此,如果我们可以把最近想要访问的那些,页表像的副本,把它存到这个快表这种高速缓存当中,那么CPU在地址变换的时候,查询页表的这个速度就会快得多了,所以这是快表要比慢表更快的一个,大致的原理,不过也需要注意快表TRB,它和我们平时所说的那种,狭义上的啊,高速缓存,狭义上的catch其实也是有区别的,那具体有什么区别,我们在这个小节的最后会给大家,进行一个简要的提示,这我们只需要知道,快表的查询速度要比慢表啊快很多,就可以了,那接下来我们要探讨的问题是,既然快表,的查询速度快那么多那
那能不能把整个页表都放在,块表当中呢,其实这个原因不难理解,因为块表这种存储硬件的造价更贵,因此在成本相同的情况下,块表可以存的东西肯定呃没有那么多,这就类似于什么呢,如果大家在生活当中想要,找某一种容器来存自己的书本的话,那么可能会想到的是买一个书架,因为书架上面可以存好多好多的书,但是虽然书架的容量大,然而,当我们想要取书架中的这些书的时候,其实是不方便的,如果我们人在外面,那我们是不是还得跑回家,去书架上拿自己的课本,因此书架的存取速度要更慢,但是它的优点呢就是成本更低更便宜,为了解决这个问题我们的办法是什么,我们可以买一个小书包,虽然书包的价格更高,但是它的存取速度更快,然而相应的在同等价格的情况下,书包的容量肯定没有书架这么多,不过我们可以把我们最近要用到的书,放到我们的小书包里,这样的话,我们既可以方便快速的,拿取我们想要访问的那些书本,同时我们还可以压低控制我们的成本,所以,我们系统当中存储分级的这个思想,和我们这提到的这个例子,其实是一模一样的,那我们可以去网上,搜一下就是这些存储设备,它的成本到底有多高,你看这个ETB的硬盘,它的呃价格就200多块钱,但是比它快很多的这个内存,虽然它的存储能力只能存8GB,但是它的价格,反而要比ETB的硬盘要高很多,因此虽然越往上的这种存储设备,它的速度越快,但是同时它的造价成本也会,指数级的上升,所以为了兼顾系统整体的运行效率,同时也要考虑这个造价成本,因此才采用了这种多级的存储设备,好的,那么刚才我们从硬件的角度理解了啊,快表为什么要比慢表更快,那接下来,我们,再从这个操作系统的角度来看一下,快表
到底有什么作用,我们来看这样一个例子,假设某一个进程他在执行,的过程中,需要依次访问这样的几个逻辑地址,那前面的这个是指页号,后面的这个指的是呃页内偏移量,这个进程的页表存放在内存当中,是这个样子,那当这个进程上处理机运行的时候,系统会清空快表的内容,注意啊快表是一个专门的硬件,当进程切换的时候,快表的内容也需要被清除,那我们假设,访问快表,访问TRB只需要一微秒的时间,而访问内存需要100微秒的时间,接下来,我们来看一下快表是如何工作的,那首先这个进程他想要访问的,逻辑地址是页号为0,页内篇一量也为0的这个逻辑地址,首先这个页号需要和,页表寄存器当中的页表长度,进行一个比对,进行越界异常的检查,然后发现这个页号并没有越界,接下来就会查询快表,但是由于这个进程刚上处理机运行,因此快表此时的内容是空的,在快表中找不到页号为0,所对应的页表象,因此快表没有命中,那由于快表没有命中,因此接下来就不得不,去访问内存当中存放的慢表,所以接下来通过页表食指还有页号,计算出对应的页表象存放的位置,于是在查询完慢表之后就可以知道,0号页面他所存放的内存快号是600,注意在访问了这个页表像之后,同时也会把这个页表像把它复制一份,放到快表当中,同时刚才不是已经查到,这个页面所对应的内存快号了吗,那么通过这个内存快号和页内篇一量,就可以得到最终的物理地,址最后,就可以访问,这个逻辑地址所对应的内存单元了,那这是进程访问的第一个地址,接下来,这个进程想要访问的地址是页号为0,页内偏移量为4的啊这个地址,那同样的,刚开始会进行一个越界异常的判断,发现没有越界,所以接下来会根据页号来查询块表,需要确认一下,这个页号所对应的页表项,是否在块表当中,那由于刚才,我们已经把它复制到了块表当中,因此这一次的查询就可以命中,而快表命中之后,系统就可以直接知道,0号页面它存放的内存快号是600,因此接下来,它就不需要再查询内存当中的慢表,而是直接,用这个内存快号和页内篇一量,得到最终想要访问的物理地址,然后进行访存,因此如果快表命中的话,就不需要再访问内存中的慢表了,那最后的这个地址其实也是一样的,嗯也是会先进行越界的检查,然后查询快表结果,快表命中,于是系统可以直接,根据查询快表的结果,得到最终的这个物理地址,然后访问最终需要访问的这个,内存单元,那如果这个系统中没有快表的话,每一次地址变换的过程,肯定都需要查询内存中的慢表,而查访问一次内存需要100微秒的时间,因此每一次地址变换都需要花100微秒,而如果说引入了快表的话,那只要快表命中,我们的地址变换过程,就只需要花费一微秒的时间,所以这也是为什么快表能够加快,地址变换的一个原因,那需要注意,的是快表中存放的是,进程页表当中的一部分副本,因为之前我们已经说了,快表虽然速度更快,但是造价其实也要比内存高很多,因此为了控制成本,快表的容量就不会特别大,所以快表当中只有可能存放,慢表中的一部分,页表上的副本,不过这已经可以让系统的效率,有很大的提升了啊,这个我们之后还会继续细聊,那接下来我
用文字的方式来总结一遍啊,引入了快表机构之后啊,地址变换的过程,首先通过这个逻辑地址,我们可以得到页号和页内偏离量,然后进行了越界判断之后,会把这个页号,和快表当中的所有的这些,页号进行对比,只不过查询快表的速度,要比查询慢表的速度快很多,如果快表命中,也就是找到了这个页号,对应的表象的话,那么就可以直接,通过快表当中存放的那些信息啊,直接得到最终的物理地址,最终,在访问我们想要访问的那个内存单元,所以在引入了快表机构之后,如果快表命中的话,我们访问一个逻辑地址,只需要一次访存,也就是访,问我们最终想要访问的那个地址单元,的时候才需要访存,而地址转换的过程当中不需要访存,当然如果快表没有命中的话,那么我们依然需要访问啊,内存当中的页表,所以在这种情况下,我们要访问一个逻辑地址,就需要两次访存,第一次访存,是查询内存当中存放的页表,第二次访存,是访问,我们最终想要访问的那个内存单元,那需要注意的是在我们查询慢表之后,同时也需要把慢表当中的页表像,给它复制到快表当中,而如果快表已经存满了,那么我们需要按照一定的算法,淘汰,快表当中的某一些页表像进行替换,那这个是我们之后,置换算法当中会学习的一个内容,这儿就暂时不展开,总之在引入了快表之后,系统在进行地址变换的时候,他会优先查询快表,只有快表没有命中的时候,他才会去查询啊内存当中的页表,那由于查询快表的速度要比查询,慢表的速度啊快很多,所以这就可以啊,使这个系统的整体效能得到提升,系统的整体效能得到提升,基于局部性原理,一般来说,快表的命中率可以达到90%以上,什么是局部性原理我们一会再解释,我们先来看一下,假设快表的命中率可以达到90%的话,它到底可以让这个啊系统,性能提升多少,我们假设某一个系统,它具有快表啊这种地址变换机构,那访问一次快表耗时一微秒,访问一次内存耗时100微秒,如果快表的命中率为90%的话,我们来算一算在这种情况下,访问一个逻辑地址平均耗时是多少,那根据上面的分析我们知道,系统在访问一个逻辑地址的时候,他首先会查询快表,会消耗一维秒的时间,如果快表命中的话,那么系统就可以直接得到,最终想要访问的物理地址,并且,访问这个物理地址对应的内存单元,那访问这个内存单元,总共需要100微秒的时间,所以如果块表命中的情况下,访问这样的一个地址,总共就需要耗费1+100这么多的时间,那它的命中率是90%,所以我们给它乘上0.9的权重,那再来看第二种情况,如果快表没有命中的话,首先系统会查询快表,消耗一维秒的时间,接下来由于快表没有命中,所以系统需要访问内存当中的慢表,查询慢表其实就需要访问一次内存,所以这就需要消耗100微秒的时间,那得到最终的物理地址之后,还需要访问最终想要访问的内存单元,因此这还需要再加上100微秒,那发生这种情况的概率是10%,所以我们给他乘上0.1的权重,那最终我们就可以得到,如果是这种情况的话,那访问一个逻辑地址的平均耗时,就应该是111微秒,那如果这个系统没有快表机构的话,那每一次访问逻辑地址,肯定都需要先查询内存中的漫表,然后最终再访问我们的目标内存单元,所以如果没有快表的话,那系统访问一个逻辑地址,所需要的耗时就应该是200微秒,因此在引入了快表机构之后,可以看到,这个呃效能的提升还是有很多的,从200微秒变成了111微秒,那这个地方需要给大家提个醒,有的系统中,可能会支持快表和慢表同时查询,那如果是这样的话,平均耗时就应该是这么多,那唯一的区别就在于,快表没有命中的时候,啊这的一不见了,这点我们一会用干特图,让大家更好的理解,总之大家在,做题的时候啊需要注意的点就是啊,题目当中有没有告诉你,快表和慢表是同时查找的,还是说只有快表查询未命中的时候,再查询慢表,那不管怎样在引入了快表之后,肯定这个地址变换的过程都快了很多,系统效能得到了大幅度的提升,那接下来我们来解释一下
刚才所说的这个快表和慢表同时查找,到底是什么意思,我们的第一个例子当中,我们是默认了系统先查询快表,也就是先消耗了一微秒的时间,当快表查询未命中的时候,他才会开始查询慢表,那查询慢表的过程,又需要消耗100微秒的时间,而如果快表和慢表同时查询的话,情况就会变成这样,快表和慢表是同时开始查询的,而在一微秒的时候,系统发现这个快表查询未命中,但是在这个时刻,其实慢表也已经查了一微秒的时间了,因此接下来再消耗99微秒,就可以得到这个慢表的查询结果,那通过这个干特图,相信并不难理解,什么叫快表和慢表同时查找,什么叫先查快表,快表未命中的时候再查慢表,这是做题的时候,大家需要注意的一个小细节,那接下来我们来思考一个问题,为什么TRB当中,只存放了页表中的一部分,就可以让系统的效能提升那么多呢,这其实因为
著名的局部性原理,我们来看一个例子,这段程序当中我们定义了一个长度,为100的数组,并且用一个循环,来呃访问这个数组当中的各个元素,那么假设对于这个进程来说啊,他的这些程序的指令,是存放在10号页面当中的,而这个程序当中的这些变量,比如说数组还有变量i,这些变量是存放在23号页面当中的,那么在这个程序运行的过程当中,他肯定就会频繁的来访问,10号页面和23号页面,因为10号页面当中,存放的是他的这些代码指令,由于他有这种循环的结构,因此在执行这个程序循环的时候,无非就是一直在访问这个循环,所对应的那几条指令,所以他会频繁的访问到10号页面,那这就是所谓的时间局悟性原理,也就是说,如果程序执行了某条指令之后,那么在接下来的不久,这条指令很有可能会被再次执行,比如说在这个循环中,爱佳佳所对应的指令,肯定是会被频繁的执行的,另外呢当某个数据被访问过之后,不久之后,这个数据还有可能会被再次访问,就像这个变量i,变量i这个数据,它是存放在23号页面当中的,那由于存在这个循环,因此这个数据有可能会被,频繁的再次访问,这就是时间局部性,那还有一个概念叫空间局部性,是指,一旦程序访问了某个存储单元之后,不久之后,其附近的存储单元有可能会被访问,就比如说这个循环中,我们访问了这个数组a,也就是这个数组当中的各个元素,而这个数组在内存中,其实是连续的存放的,因此,当程序访问了某一个存储单元之后,不久之后,可能,附近的存储单元也有可能会被访问,那结合这个例子,相信局部性原理并不能理解,那由于局部性原理,也就是说这个程序在某段时间内,可能会频繁连续的,访问某几个特定的页面,因此在地址变换的过程中,只要他访问的是同一个页面,那么他查询页表的时候,其实查到的也都是同一个页表项,所以只要我们把慢表当中的页表像,把它复制到快表当中,那这样就可以让地址变换的速度啊,快很多了,因为就不需要每次查询慢表,那这就是为什么快表机构能够,啊大幅度的提升系统效能的一个原因,好了那
那这个小节中,我们介绍了具有快表的地址变换机构,在没有引入快表之前,我们访问一个逻辑地址,至少需要两次访存,第一次访存是查询内存当中的页表,第二次访存,才是访问我们最终想要访问的,啊那个内存单元,而在引入了快表之后,如果快表命中的话,那么就只需要一次访存,如果快表未命中的话,我们仍然需要两次访存,仍然需要查询内存中的漫表,那最后我们还需要强调一下,TRB和我们普通的catch,普通的高速缓存有什么区别,通过这个小节的学习大家不难发现,TRB当中我们只存有页表像的副本,存放的是页表像的副本,而普通的高速缓存当中,存放的是其他数据的副本,所以TRB和catch还是有区别的,不能混为一谈,好的,那么以上就是这个小节的全部内容,
No.9 两级页表
各位同学大家好,在这个小节中,我们会介绍两集页表,相关的一系列知识点,那两级页表,其实是为了解决单,级页表当中存在的一些,问题,所以我们会从单级页表存在的问题,着手开始分析,并且分析如何解决这些问题,由此引出两级页表机制,那么两级页表的原理逻辑地址结构,还有地址变化的过程,这是咱们之后会讲解的内容,最后我们还会强调几个两级页表问题,在考试当中有可能会,作为考点的一个很重要的几个细节,那我们会按照从上至下的顺序,依次讲解首先来
看咱们之前介绍过的单几页表机制,存在什么问题,假设一个计算机系统按照字节选址,支持32位的逻辑地址,那么采用分页存储管理,页面大小是4KB页表像长度是4个字节,那既然一个页面的大小是4KB,也就是2的12次方格字节,所以在这32位的逻辑地址当中,需要有12位来表示业内地址,然后剩余的20位才是表示业号,那既然有20位表示页号,也就意味着,一个用户进程,最多有可能有2:20次方个页面,而我们知道,每一个页面需要对应一个页表像,那么这么多的页面,就需要的对应同等的2-20次方个页表像,而每个页表像的大小是4个字节,所以总共就需要2-22次方个字节,来存储这个进程的页表,那这么多的字节,总共就是2的10次方格叶框,也就是1024个叶框,但是之前咱们讲过,为了实现通过页号,查询对应的页表像这件事情,那么一般来说,整个页表都是需要,连续的存放在内存当中的,因此在这个系统当中,一个进程,光他的页表就有可能需要占用,连续的1,024个页框来存放,那要为一个进程分配,这么多的连续的内存空间,这显然是比较吃力的,并且这已经丧失了我们,离散分配,这种存储管理方式的最大的一个优点,所以这是单级页表存在的第一个,很明显的缺陷问题,那第2个问题
由之前我们介绍过的局部性原理,我们可以知道,很多时候,其实进程在一段时间内,只需要访问某几个特定的页面,就可以正常的运行了,因此我们没有必要让,进程的整个页表都常驻内存,我们只需要让,进程此时会用到的那些页面,对应的页表,像在内存当中保存就可以了,所以这是单级页表存在的第二个问题,那么从
从刚才的分析当中我们知道,单机页表存在两个明显的问题,第一个问题就是页表必须连续的存放,所以如果页表很大的话,那么光页表就需要,占用连续的很多个页框,那这和我们,离散分配存储管理的这种思想,其实是相对的,所以我们要尝试解决这个问题,那第二个问题就是,我们没有必要让整个页表都常驻内存,因为进程在一段时间内,可能只需要访问某几个特定,的页面就可以顺利的执行了,那这是基于局部性原理啊,得出的一个结论,那我们首先讨论,第一个问题应该怎么解决,其实我们可以参考一下我们之前,解决进程在内存当中必须,连续存储的这个问题的时候,提出的那种思路,那我们之前的做法其实很简单,就是把进程的地址空间进行分页,然后再为进程建立一张页表,用来记录他的各个页面之间的顺序,还有呃保存的位置这些信息,那同样的思路,其实我们也可以用来解决,一个页表必须连续存储,连续占用多个页框的问题,那我们可以把,呃这个很长的页表进行分组,让每一个内存化,刚好可以放入一个分组,比如说像之前那个例子当中,我们的页面呃,一个页面可以存放1K个页表,像所以我们可以,让每1K个连续的页表相为一组,然后这样的一组,就可以刚好占满一个内存块,然后再把这些各个分组,离散的分配到各个内存块当中,那为了保证我们把这些分组离散的放,放到各个内存块之后,还能够知道这些分组之间的先后顺序,此我们依然是,像需要模仿之前的这种思路,为这些分组再建立一个页表,然后这个页表就称为页目路表,或者叫外层页表或者叫顶层页表,当然408呃的真题当中,比较喜欢用的是页目路表这个名词,那这个地方观看这些文字描述,会比较抽象,我们直接结合图像来,进行进一步的理解
男孩沿着刚才的例子进行分析,32倍的逻辑地址空间,页表向大小为4比页面大小为4KB,所以页内地址应该是占12位,其余的20位才是页号,所以,如果我们采用的是单级页表结构的话,逻辑地址结构应该是这样子,那既然我们的页号有20位,就意味着在这个系统当中,一个进程,最多有可能会有2-20次方个页面,那相应的也会有2-20次方个页表项,呃如果用实径值表示的话,这些页表下的编号应该是0到1048575,这其实就是2-20次方减一这么一个数,那现在由于这个呃页表的长度过大,所以我们按照之前所说的那种思路,我们可以把这么大的一个长长的页表,把它拆分成一个一个的小分组,那每个小分组的大小,可以让它刚好能够呃装入一个内存块,那我们每个内存块,或者说每个页面的大小是4KB,而页表箱的大小是4B,所以一个内存块一个页面可以存放4K,除以4也就是1K个页表箱,那么换算神石径制,就应该是102四个页表箱,因此我们可以把这么大的页表,拆分成一个一个小分组,每一个分组的呃页表像有1024个,就像这个样子,另外我们可以给这些小页表进行编号,0号页表1号页表和一直到102三个页表,那进行这样的拆分之后,最后总共就会形成1024个呃,一个一个的小页表,那这个地方可以稍微注意一下的是,以前在这个大页表当中,编号为1024的这个页表像,在进行拆分以后,应该是变成了第二个,小页表当中的第一个页表像,所以可以看到,这个页表像和这个页表像的这个块号,是一样的,只不过页号就是变为了从0开始,那我们继续往下分析
再把大页表,拆分成这样一个一个小页表之后,由于每一个小页表的大小都是4KB,因此每一个小页表都可以依次放到,呃不同的内存块当中,所以,为了记录这些小页表之间的相对顺序,还有他们在内存当中存放的块号位置,那我们需要为这些小页表再进行,再建立上一集的页表,这级的页表就叫做页目录表,或者叫顶级页表外层页表,那相应的,这层的小页表,我们可以把它称为二级页表,那从这个图当中也可以很直观的看到,页目录表其实是建立了,二级页表的页号,还有二级页表,在内存当中存放的快号,之间的一个映射的关系,所以,如果此时我们想要找到0号页表的话,那么我们可以通过页目录表,就可以知道,0号页表是存放在3号内存块里的,所以只需要在3号内存块这个地方,来找0号页表就可以了,那在采用了这样的两级页表结构之后,逻辑地址的结构,也需要发生相应的变化,我们可以把以前的20位的,夜号拆分成两个部分,第一个部分是十位的二进制,用来表示一级也好,第二部分也是十位二进制,用来表示二级也好,那十位的,二进制大家会发现,刚好是可以表示0-1023这么一个范围,所以用一级夜号来表示这个范围,是刚好的那,是刚好的,那相应的,二级页号的这10个二斤之位,就是用来表示二级页表当中的这些,呃页号,那接下来我们再结合这个例子,来看一下,我们应该怎么实现地址的变化
把逻辑地址这么一串东西,转换成物理地址,并且最后的物理地址用实径值表示,那么要进行这个地址变化,我们要做的第一件事情,就是根据呃我们的,地址结构,把逻辑地址拆分成三个部分,也就是一级也好,二级也好,还有页内偏移量这么三个部分,那第二步,我们可以从PCB当中知道,我们的页目录表,在内存当中存放的位置到底是哪里,那这样的话,我们就可以根据一级页号来查询,页目录表了,那一级页号是0,所以我们查到的表象应该是这个表象,那从这个页表项当中我们可以知道,0号的二级页表,存放在内存快号为3号的地方,也就是这个位置,所以我们可以从这个位置读出,啊二级的页表,然后开始用二级页号来再进行查询,那二级页号是一,所以我们查询到的,页表项应该是这一项,那通过这个页表项我们就可以知道,最终我们想要访问的地址,应该是在4号内存快里的,所以接下来我们就可以根据,呃最终要访问的内存快号,和页内篇一量,得出我们最终的物理地址了,那由于我们想要访问的是4号内存快,并且每个内存快大小是4 k b,也就是4096个字节,所以4号内存快的起始地址应该是4,乘以4096就等于16384,另外,页内偏移量把它转换为实进制之后,应该是1023,所以我们可以用内存块的起始地址,再加上页内偏移量的这个数字,就可以得到最终的物理地址17407了,那经过刚才的一系列分析
我们就解决了,我们之前提出的第一个问题,当页表很大的时候,其实我们可以采用,两级页表的这种结构,来解决这个页表必须,连续的占用多个页框的问题,那接下来我们再来看一下第二个问题,应该怎么解决,其实,如果说不让整个页表长出内存的话,那么我们可以在需要访问页面的时候,才把页面调入内存,其实这是咱们之后会介绍的,虚拟存储技术,这个在之后的小节当中,会有更详细的介绍,这只是先简单的提一下他的思想,那我们可以给每一个页表像,增加一个标志位,用来表示,这个页表像对应的,页面到底有没有掉入内存,那如果说此时想要访问的那个页面,暂时还没有掉入内存的话,那么就会产生一个缺页中断,然后操作系统负责,把我们想要访问的那个目标页面,从外存掉入内存,那缺液中断肯定是我们在执行,某一条指令,这个指令想要访问到,某一个暂时还没有掉入的页面,的时候产生的,所以这个中断信号,和当前执行的指令有关,因此这种中断应该是属于内中断,那这个部分的内容,咱们在之后的小节当中,还会有更详细的介绍,那接下来我们再来强调
要几个,在考试当中需要特别注意的小细节,第一个,如果我们采用的是多几页表机构的话,那么,各几页表的大小不能超过一个页面,那这个限制的条件,我们在做题的时候应该怎么应用呢,我们直接来看一个例子,假设某系统按字节编制,采用40位逻辑地址结构,然后页面大小14KB页表箱是4比,如果采用的是纯页式存储的话,需要采用几级页表呢,页内篇译量又是多少位呢,那我们首先最容易确定的,应该是页内偏移量的位数,每个页面的大小是4 k b,而这个系统是按字节编织的,所以呃页内偏移量应该占12位,而剩余的28位,就应该是用来表示页号的,另外由于每个页面的大小是4 k b,而每个页表像是4B,所以一个页面,可以存放2的10次方格页表像,也就是1024个页表像,那由于采用多级页表的时候,各级页表的大小不能超过一个页面,所以说各级页表当中,页表项最多不能超过2的10次方格,那相应的,各级业号所占的位数也不能超过10位,所以28位的业号,我们可以把它分成三个部分,一级业号占8位二级业号10位,三级业号也占10位那,相应的这样的话,我们就需要再建立更高一级的页表,最终会形成3级页表的一种结构,那3级页表的原理和两级页表的原理,其实是一模一样的,这个地方就不再展开追溯,那这个地方,假如说我们只是采,用了两级页表的结构的话,那么低级的页号就会占18位,也就是说在页目录表当中,最多有可能会有2的18次方格页表像,那这么多的页表像,显然是呃不能放在一个页面里的,所以这就违背了采用多级页表的时候,各级页表的大小不能超过一个页面,这样的一个条件,因此,如果我们只把它分成两级是不够的,那这就是我们需要注意的第一个细节,这个很有可能作为考点在选择题,甚至是结合大题来进行考察,第二个我们需要注意的点是,两级页表的访存次数的分析,假设我们没有采用快表机制的话,那么第一次访存应该是,访问内存当中的页目录表,也就是顶级页表,第二次访存应该是,访问内存当中的二级页表,第三次访存,才是访问最终的目标内存单元,所以采用两级页表结构的话,我们要访问一个逻辑地址,需要进行三次访存,还记得我们分析的单级页,表的访存次数,问题吗,如果采用的是单级页表结构的话,那么第一次访存就是查询页表,第二次访存就是,访问我们最终想要访问的内存单元,所以,单级页表在访问一个逻辑地址的时候,只需要进行两次访存,因此两级页表虽然解决了我们之,前提出的单级页表的那,两大问题,但是这种内存空间的利用率的上升,付出的代价就是,逻辑地址变换的时候,需要进行更多一次的访存,这样的话,就会导致我们要访问某一个,逻辑地址的时候,需要花费更长的时间,所以这是,两级页表相比于单级页表来说的一个,很明显的缺点,那如果我们继续分析三级页表,四级页表,结构当中的访存次数的话,会发现三级页表,访问一个逻辑地址需要访存4次,四级页表需要访存5次,五级页表需要访存6次,所以其实有一个规律,如果是没有块表机构的话,那么,n级页表在访问一个逻辑地址的时候,访存次数应该是n加一次,那这就是我们需要注意的,两个很重要的小细节,好的那么这个小节当中
我们介绍了两级页表相关的知识点,我们从单级页表存在的两个问题出发,来依次探讨了这两个问题,应该怎么解决,特别是第一个,那采用了两级页表结构之后,我们就可以解决第一个问题,但是第二个问题的解决需要采用啊,虚拟存储技术,这个咱们会在之后的小节进行,更详细的讲解,那在本节当中,我们需要重点理解,两级页表的逻辑地址结构,还需要注意,页目录表,外层页表顶级页表这几个说法,不过在408当中,最常用的是页目录表这个术语,另外大家也需要理解,采用了两级页表之后,如何实现逻辑地址,到物理地址的转换,那这个转换过程,其实和咱们之前介绍的单级页表,并没有太大的差异,无非就是还需要多查一集的页表而已,那这个过程需要能够自己分析,那最后,我们强调了两个我们需要注意的小细,节第一个小细节,多级页表当中,各级页表的大小不能超过一个页面,所以说如果两级页表不够的话,那么我们可以进行更多的分解,第二个小细节,我们也需要自己能够分析,多级页表的访存次数,那n级页表访问一个逻辑地址,是需要n加一次访存的,另外大家还需要能够根据,题目给出的逻辑地址位数,页面大小,页表像大小这几个条件,来确定多级页表的逻辑地址结构,那这些内容,还需要大家结合课后习题,来进行巩固和消化,好的,那么以上就是这个小节的全部内容
No.10 基本分段存储管理方式
各位同学大家好,在这个小节中,我们会学习另一种离散分配的存,储管理方式,叫基本分段存储管理,那这种管理方式,和咱们之前学习的分,页存储最大的区别,其实就是,离散分配的时候,所分配的地址空间的基本单位,是不同的,这个小节中我们会啊,首先介绍什么是分段,那分段的这个概念思想,其实有点类似于我们分页,存储管理当中的分页,而之后我们会介绍什么是段表,段表就有点类似于分页,存储管理当中的页表,另外在离散分配存储管理方式当中,咱们避免不了一定要谈的问题,是怎么实现地质变化,最后,我们会对分段和分页这两种管理方式,进行一个呃对比,那我们会按照从上至下的顺序,依次讲解,那首先来看一下什么是
进程的地址空间,会按照程序自身的逻辑关系,划分为若干个段,比如说一个进程a它的大小是16 k b,那么按照它自身的逻辑关系,它有可能会被分为若干个段,那每一个段,就代表一个完整的逻辑模块,比如说0号段的啊段名叫may,然后0号段,存放的就是MA函数相关的一些东西,1号段存放的是啊一个某一个子函数,2号段存放的是啊,进程a当中某些局部变量的这些信息,那可以看到每一个段都会有一个段名,这个段名是程序员在编程的时候,使用的另外呢,每个段的地址都是从0开始编制的,所以进程a本来是有16K的地址空间,那分段之后第一个段0号段,它的地址空间就是0-7 k减一,总共的大小就是7 k b,然后1号段是0-3 k减一总共的大小是3 k b,啊 2号段也一样,那操作系统在为,用户进程分配内存空间的时候,是以段为单位进行分配的,每个段在内存当中,会占据一些连续的内存空间,并且各段之间可以不相邻,比如说,0号段占据的是从80K这个地址开始的,连续的4KB的内,存空间,而1号段占据的是从120K这个地址开始,连续的3KB的地址空间,由于分段存储管理当中,是按照逻辑功能来划分各个段的,所以用户编程会更加方便,并且程序的可读性会更高,比如说用户可以用低级语言,汇编语言写这样两条指令,那第一条指令是把分段d当中的,a单元内的值读到寄存其一中,第二个指令,是把寄存器一当中的呃内容,存到x分段当中的b单元当中,那由于各个分段,是按逻辑功能模块来划分的,并且这些段名也是用户自己定义的,所以用户在读这个程序的时候就知道,这两句代码做的事情,就是把某个全局变量的值呃付给,x这个子函数当中的某一个变量,因此对于用户来说,采用了分段机制之后,程序的可读性还是很高的,那在用户编程的时候,使用的是段名来操作各个段,但是在CPU具体执行的时候,其实使用的是段号这个参数,所以在编译程序,其实会把这些段名转换成呃,与他们各自相对应的,这些一个一个的段号,然后CPU在执行这些指令的时候,是根据段号来区分各个段的,那在采用了分段机
之后啊,逻辑地址结构就变成了这个样子,由段号和段内地址,或者叫段内偏移量组成,比如说像这个例子当中,段内地址是占了0-15总共16位,然后段号是16-31总共占了也是16位,那在考试当中我,们需要注意的一个,呃很高频的考点就是,段号的位数,决定了每个进程最多可以分多少个段,而段内地址的位数,决定了每个段的最大长度是,多少,那我们以这个例子呃为例来看一下,16位的段号和16位的段内地址,最大可以支持几个分段啊,每个段的最大程度又是多少,那我们假设这个系统是按字节编制的,也就是说,一个地址对应的是一个字节的大小,那段号占16位,所以在这个系统当中,每个进程最多可以有2的16次方个段,也就是64K个段,因为16位的二径之数最多也就能,表示这样一个范围的数字,那同样的,段的地址也是占16位,并且这个系统是按字节编制的,所以每个段的最大长度应该是2:16次方,啊也就是64KB这样的一个大小,那刚才我们提到的这两句用汇编,语言写的,指令在经过编译程序编译之后,段名会被翻编译程序,翻译成对应的段号,而这里提到的a单元,b单元这样的助记符,会被编译程序翻译成段内壁纸,也就是呃这个第二个部分,就像这个样子,每个段名会被翻译成,与他们对应的各个段号,另外各个段之间的这些,用助记符表示的内存单元,会被最终翻译为这个段,当中的段内壁纸,那这就是分段,相关的一些最基本的概念,那接下来,
我们再来看啊下一个问题,既然我们的程序被分为了多个段,并且各个段是离散的,存储在内存当中的,为了保证程序能够正常的运行,所以操作系统必须能够保证,要能从物理内存当中,找到各个逻辑段存放的位置,因此为了记录各个段的存放位置,操作系统会建立一张断印射表,简称断表,就像这样子,那用断表记录了各个逻辑段,在内存当中的存放的位置,那这个地方大家会发现,断表的作用,其实和咱们之前学习的页表的作用,是比较类似的,页表是建立了,各个逻辑页面,到实际的物理页框之间的映射关系,而段表是记录了各个逻辑段,到实际的物理内存存放位置之间的,映射关系,那每个段表由段号段长和段基值组成,这个段基值其实就是呃,段在内存当中的存放的起始位置,从这个图当中我们也能很直观的看到,每个段会对应一个段表相,那相比于页表来说,段表当中多了一个呃更不同的信息,就是段长,因为每个分段的长度可能是不一样的,而我们在分页存储管理当中,每个页面的长度肯定都是一样的,所以在分页存储管理当中,页长是不需要这样写示的记录的,是在分段存储管理当中,段的长度是需要这样显示的,记录在段表当中,那第二点我们需要注意的是,我们的各个段表项的长度,其实是相同的,也就是说,这些一行一行的段表项,在内存当中所占的,空间是大小是相同的,比如说这个系统按照字节选址,并且采用分段存储管理方式,逻辑地址结构段内地址是16,位段的长度不可能超过2的16次方字节,所以在各个段表相当中,用16位就肯定可以表示,这个段的最大段长了,假设这个系统的物理内存大小是4GB,那也就是2的32次方个字节,那这么大的物理内存的地址空间,可以用32位的二进制来表示,所以对于基质,也就是内存的某一个地址这个数据,我们只需要用32个二进之位就可以表,示了因此,每个段的段表项其实只需要16+32位,也就是48位,总共6个字节就可以表示一个段表项,因此在这个系统当中,操作系统可以规定,每一个段表象的长度,就是固定的6个字节,前两个字节表示的是段长,而后面4个字节,表示的是这个段存放的,在内存当中的起始地址,所以和页表类似,这个地方的页号可以是隐含的页号,并不占存储空间,那我们在查询断表的时候,只要我们能够知道断表,在内存当中的起始地址m,那我们想要查询k号段对应的段表项,那我们只需要用段表的起始地址m,再加上k,乘以每个段表项的大小6个字节,那就可以得到我们想要找到的那个段,对应的段表项,在内存当中的什么位置了,所以即使这个段号是隐含的,没有显示的给出,但是我们依然可以根据段号来查询,这个段表,那接下来我们再来看一下,采用了分段存储管理之后,地址变换的过程是什么样
那还是以刚才提到的这个指令为例,这个用汇编语言写的指令,经过编译程序编译之后,会形成一条等价的机器指令,比如说这条机器指令就是告诉呃,CPU从段号为2,段内地址为1024的这个,内存单元当中取出内容,放到寄存器一当中,不过在计算机硬件看来,段号段内地址这些呃逻辑地址,其实是用二进制表示的,比如说是这个样子,那前面的红色的这16位表示的是段号,而后面的黑色的这16位,表示的是段内地址,所以CPU在执行指令的时候,或者说在访问某一个逻辑地址的时候,需要把这个逻辑地址变化为物理地址,那我们看一下具体的变换过程,在内存的
那系统区当中,存放着很多用于管理,啊系统当中的软硬件资源的数据结构,包括进程控制快PCB,也是存放在系统当中的,那当一个进程要上处理及运行之前,进程切换相关的那些内核程序,会把啊进程的运行环境给恢复,这就包括一个很重要的硬件寄存器,啊当中的数据的恢复,这个寄存器叫做断表寄存器,用于存放这个进程,对应的断表在内存当中的起始地址,还有这个进程的断表长度到底是多少,因此断表存放的位置,还有断表长度这两个信息,在进程没有上处理机运行的时候,是存放在进进程的PCB当中的,那当进程上处理机运行的时候,这两个信息会被放到呃很快的断表寄,存器当中,那当知道了段表的起始地址之后,就可以知道,段表是存放在内存当中的什么地方,那接下来这个进程运行的过程当中,呃避免不了要访问一些逻辑地址,比如说要访问逻辑地址a,那么系统会根据逻辑地址得到段号,s和段内地址w,这是第一步要做的事,第二步知道了段号之后,需要用段号和段表长度进行一个对比,来判断一下段号是否产生了越界,如果段号大于等于段表长度的话,就会产生越界中断,那么接下来就会由中断处理程序,来负责处理这个中断,如果没有产生中断的话,就会继续执行下去,这个地方稍微注意一下,段号是从0开始的段表长度至少是一,所以啊当s等于m的时候,其实也是会产生啊越界中段的,那在确定这个段号是合法的,没有越界之后,就会根据,段号还有段表食指来查询段表,找到这个段号对应的段表项,那之前咱们提过,由于各个段表项的大小是相同的,所以用段表食指再加上段号,乘以段表项的长度,就可以找到我们要找的目标段,对应的段表项在内存当中的位置了,接下来就可以读出这个断表项的内容,第四步,在找到了这个段号对应的断表项之后,系统还会对,啊这个逻辑地址当中的段内地址w,进行一个检查,看看他,是否已经超过了这个段的最大断长,那如果段内地址大于等于,这个段的断长的话,就会产生一个越界,中断否则继续执行,这一步也是和我们夜视管理当中,区别最大的,一个步骤,因为在夜视管理当中,每个页面的页长肯定是一样的,所以系统并不需要检查,页内偏移量是否超过了页面的长度,但是在分段存储管理方式当中又不同,各个段的长度不一样,所以一定需要对段内地址,进行一个越界的检查,所以这一步是需要着重注意的,那我们继续往下,因为我们,此时已经找到了目标段的段表象,所以我们就知道目标段,存放在内存当中的什么地方,那最后我们根据这个段的机制,也就是这个段在内存当中的起始地址,再加上这个最终要访问的段的地址,就可以得到我们最终,想要的物理地址了,我们以之前提到的这个逻辑地址为例,进行一次完整的分析,如果说,此时要访问的逻辑地址的段号是2,然后段内地址是1024的话,那首先需要用段号2和段表长度,m进行一个检查,那显然,此时这个进程的段表长度应该是3,因为它有三个段,所以段号是小于段表长度的,因此段号合法,所以就可以进行下一步,用段号和段表食指查到啊,这个段号对应的段表项,那这样的话,就找到了2号段对应的段表项,那接下来,需要对段内地址的合法性,进行一个检查,段内地址和段长对比,发现2号段的段长是6K,而段内地址是1024也就是1K,所以段内地址是小于段长的,因此在这个地方并不会产生越界,中段可以继续执行下去,那接下来通过这个段表象我们知道了,啊这个段,在内存当中存放的起始地址是40K,所以用这个段的起始地址40K,再加上呃段内地址w,也就是1024,那这样的话,我们就得到了最终想要访问的目标,内存单元,也就是a那个变量存放的位置,那这样的话,就完成了对这个逻辑地址的一个访问,那分段,存储管理当中的这个地址变换的过程,需要和分页存储管理的过程,进行一个对比记忆,那其实大家着重需要关注的就是,分段和分页最大的区别就在于,每个,在分页当中每个页面的长度是相同的,而分段当中每个段的长度是不同的,在分页管理当中,并不需要对页内偏移量,进行一个越界的检查,但是在分段管理当中,我们一定需要对,段内地址,也就是段内偏移量和段长,进行一个对比检查,那这就是分段,和分页这两种存储管理方式当中,进行地址变换过程时候,最大的一个区别,那接下来我们在
再把分段和分页这两种管理方式,进行一个呃,统一的对比,那分页当中的页是信息的物理单位,而分段当中的段是信息的逻辑单位,在分页的时候,只考虑各个信息页面的物理大小,比如说每个页面是4KB,但是在分段的时候,必须考虑到信息的这些逻辑关系,比如说某一个具有完整逻辑,功能的模块,单独的划分成一个段,那另外,分段的主要目的是为了实现理算分配,提高内存利用率,但是分段的主要目的是为了更好的,满足用户需求,方便用户编程,所以,分页其实仅仅只是系统管理上的需要,它只是一个系统行为,对用户是不可见的,也就是说,用户是并不知道自己的进程,到底是分为了几个页面,甚至,不知道自己的进程是不是被分页了,但相比之下分段对于用户是可见的,用户在编程的时候,就需要显示的给出段名,所以,用户其实是知道自己的程序会被分段,甚至知道会被分为几个段,每个段的段名是多少,另外页的大小是固定的,并且这个页面的大小是由系统决定的,但是断的长度却不固定,取决于用户,编写的程序到底是什么样一个结构,那从地址空间的角度来说,分页的用户进程地址空间是一维的,比如说一个用户进程的大小总共是16K,那么在用户看来,他的整个呃进程的逻辑地址空间,应该是从0到16 k减1,用户在编程的时候,只需要用一个记忆符,就可以表示一个地址,比如说用一个记忆符a,来表示,呃某个页面当中的某一个内存单元,但如果系统采,用的是分段存储管理的话,那么用户进程的地址空间是二维的,用户自己也知道自己的进程会被分为,012这么几个段,并且每个,段的这个逻辑地址都是从0开始的,所以在分段管理的这种系统当中,用户编程的时候既需要给出段名,也需要给出段内地址,比如说,咱们之前提到的这个汇编语言指令,用户需要显示的给出段名,还有段内地址,那因此在分页管理当中,在用户自己看来,自己的这个进程的地址空间是连续的,但是在分段存储管理当中,用户自己也知道,自己的进程地址空间,是被分为了一个一个的段,并且每个段,会占据一连串的连续的地址空间,因此,分页当中进程的地址空间是一维的,而分段的时候,进程的地址空间是二维的,那这个点在选择题当中,还是很容易进行考察的那除了
之前所说的那些不同之外,分段相比于分页来说,最大的一个优点应该是呃,他更容易实现信息的共享和保护,比如说一个生产者进程,呃总共是16KB这么大,那么他可能会被分为这样的三个段,其中1号段,是用来实现,判断缓冲区此时是否可以访问,这样一个功能,其实除了这个生产者进程之外,其他的生产者进程消费者进程,他们也需要判断,缓冲区此时是否可以访问,因此这个段当中的代码,应该允许各个生产者进程,消费者进程共享的访问,那怎么实现共享的使用这个段呢,假设我们的这个伸长者进程,他有一个这样的段表,他的1号段,也就是判断缓冲区的那个段,是存放在内存的 120K,这个地址开始的这个,内存空间当中的,那如果说消费者进城,想要和他共享的使用这个1号段的话,那么很简单可以,让消费者进城的某一个段表象,同样是指向这个段存放的起始地址的,所以如果我们想要实现呃共享的话,那么,我们只需要让各个进城的某一个段,表象指向同一个段就可以了,那这个地方需要注意的是,只有纯代码或者叫可重入代码,也就是不能被修改的代码,可以被共享的访问,那这种代码不属于临界资源,各个进程即使并发的访问,啊这这一系列的代码,也不会因为并发产生问题,比如说有一个代码段,只是简单的输出hello,word这么一个字符创,那么所有的进程并发的访问,这个代码段,那显然是不会出问题的,但是对于可修改的代码段来说,是不可以共享的,说有个代码段当中他比较复杂,有很多变量,那个进程如果,并发的同时访问这个代码段的话,那么就有可能因为并发,造成数据不一致的问题,因此对于代码来说,只有纯代码这种不属于临界资源的,代码可以被共享的访问,那这是在分段存储管理方式当中,实现共享的一个,很简单的方式,那接下来我们
我们再来看一下为什么分页管理当中,不方便实现这种信息的共享,假设我们把这个进呃消费者进行进程,进行分页的话,那么第一个页,是0号段当中的前半部分的位置,占4KB那第二个页,它会包含0号段当中的3KB,和1号段当中的1KB,那这两个总共组成了4KB的页面,那类似的第三个页,面也会包含一半1号段的内容,还有另一半是2号段的内容,所以如果采用分页这种方式的话,那么我们如果按照,消费者进城的某个页,表像,也指向这个生产者进城的分页的话,那么显然是不合理的,在生产者进程的这个分页当中,只有绿色部分是允许被消费者进程,共享的但是橙色部分,不应该被消费者进程所共享,因此由于页面它并不是按照逻辑,模块进行划分的,所以我们就很难实现共享,并不像分段那么方便,那其实对于信息的保护,原理也是类似的,比如说在生产者进程当中,1号段应该是允许被其他进程访问的,那我们只需要把这个段,标记为允许其他进程访问,其他的那些段标记为不允许其他竞争,访问那这就很简单的就实现了,对于各个段的保护,但是如果采用分页管存储管理的话,1号页和2号页当中只有一部分,也就绿色这些部分,是允许其他竞争访问的,而其他的橙色和紫色的部分,不应该允许为其他竞争访问,所以这样的话,我们其实不太方便,对各个页面进行标记,到底是否允许被其他进程访问,因此采用分页存储的时候,更不容易实现,对信息的保护和共享这两个功能,那这是关于信息的共享和保护,通过刚才的讲解相信不难理解,那接下来我们
再来探讨啊,我们在分段和分页这两种方式当中,访问一个逻辑地址需要几次访存,如果我们采用的是单级页表的分页,存储管理的话,那么第一次访存应该是查询页的内存,当中的页表,第二次访存才是查询最终的目标,内存单元,那这个这个过程,咱们在之前已经分析过很多次,就不再展开,所以采用单级页表的分页存储管理,总共需要两次访存,如果采用分段的话,第一次访存是查询内存当中的段表,第二次访存是访问目标内存单元,所以采用分段的时候,也是总共需要两次访存,那在分页存储管理当中,我们知道我们可以引入快表机构,来减少在,进行地址转换的时候查,访问内存的次数,所以其实在分段管理当中也类似,我们也可以引入快表机构,然后,可以把近期访问过的段表相放到,快表当中,那这样的话只要快表能够命中,那么我们就不需要再到内存当中查询,断表我们就可以少一次访存,那这就是分段和分页管理的一个对比
在学习了分页存储管理之后,这个小节的内容其实并不难理解,我们介绍了什么是分段,在分段存储管理当中,逻辑地址结构是什么样的,另外我们介绍了和页表很类似的段表,只不过对于段表来说,大家需要着重注意的是,每个段表相当中,一定会记录这个段的段长是多少,而在分页存储管理当中,每个页面的长度是不需要显示的,在页表当中记录的,因为各个页面的长度一样,而在分段存储当中各个段的长度是不,一样的所以这是他们俩之间的一个,最明显的一个区别,那由于各个段的段长不一样,所以在地址变换的时候,大家也需要注意啊,在找到了对应的断表项之后,还需要对,断肠和断内壁纸进行一个对比的检查,看一下断内壁纸是否越界,那除了这个步骤之外,其他的那些步骤,其实和夜市管理当中地址变换的过程,也是大同小异的,那分段和分页的对比,这些知识点,是很容易在选择题当中进行考察的,所以大家还是需要理解这些点,那这个小节的内容,还需要大家通过课后的集体,再进行进一步的实践巩固,也需要能够根据,题目当中给出的信息,来手动的完成这个地址变换的过程,好的,那么以上就是这个小节的全部内容
No.11 段页式管理方式
各位同学大家好,在这个小节中,我们会介绍断页式管理方式,那断页式管理,其实是分,段和分页这两种管理方式的一个结合,所以这个小节刚开始,我们会来分析一下,分页和分段这两种管理方式,最大的优缺点是什么,那之后我们会介绍分段和分页这两种,啊方式这两种思想的一种结合,从而引出了断页式管理方式,那之后我们还会介绍,在断页式管理当中,段表和页表,与分段分页管理当中的段表,页表有什么相同和不同的地方,那之后我们还会介绍,怎么实现,从逻辑地址到物理地址的变化那,我们会按照从上至下的顺序依次讲解,首先来看一下分页
和分段的呃优缺点,在分页管理当中,主要考虑的是,怎么提高内存空间的利用率,所以想用这种方式的话,内存空间的利用率会很高,不会产生外部碎片,只会有少量的内部碎片,但是缺点就是,由于分页是按照,信息的物理结构来进行划分的,所以呃我们不太方便按照逻辑模块,逻辑结构来实现,对信息的共享和保护,但对于分段管理来说,分段,是按照信息的逻辑结构来进行划分的,因此采用这种方式的话,就很方便,按照逻辑模块实现信息的共享和保护,不过缺点呢,就是如果说我们的段很长的话,就需要为这个段分配很长,很大的连续空间,那很多时候分配,很大的连续空间会不太方便,那另外呢,段式管理是会产生外部碎片的,它产生外部碎片的原理其实和,动态分区分配很类似,比如说一个系统的内存本来是空的,那么先后来了三个分段,他们都需要占用连续的这种存储空间,那这个地方有4兆字节的空闲区间,之后这个分段用完了,于是把它撤离内存,那接下来又来了一个分段占4兆字节,如果他占用了这个这个分区的话,那这个地方,就会产生10兆字节的一个空间,那接下来如果上面这个段也撤离了,那接下来再来了一个分段,也是占14兆字节,那这个地方就会产生,6兆字节的呃空闲的,区间,那再接下来如果还有一个分段到来,他总共需要占20兆字节的啊,这种连续的内存区间,那由于此时这些空闲区间并不连续,所以虽然他们的大小总和是20兆字节,但是这个分段是放不进呃内存当中的,因为分段必须连续的存放,所以很显然,段式管理是会产生,这些难以利用的外部碎片的,不过对于外部碎片的解决,其实和咱们之前介绍的那种,动态分区分配也一样,可以通过这种紧凑的方式,来创造出更大的一片连续的空间,但是紧凑技术,需要付出比较大的时间代价,所以显然,这种处理方式也并不是一个,很完美的解决方式,所以基于,分页管理和分段管理的这些优缺点,人们又提出了分段,和分页这两种思想的一个结合,于是产生了断页式管理,断页式管理就,具备了分页管理和分段管理的,各自的优点,再采用断页式管,
管理的,系统当中,一个进程会按照逻辑模块进行分段,之后各个段还会进行分页,比如说每个页面大小是4KB,那么0号段本来是7KB,它会被分为4KB和3KB这样两个页面,那对于内存来说,内存空间也会被,分为大小相等的内存块,或者叫页框页帧物理块,那每一个内存块的大小和,系统当中页面的大小是一样的,也就是4KB,那最后进程的这些页面,会被依次放到,内存当中的各个内存块当中,那我们在上个小节中学过如果采用
用的是分段管理的话,那么逻辑地址结构是由,段号和段内地址组成的,而在段页式管理当中我们会发现,一个进程被分段之后,各个段还会被再次分页,所以对于段页式管理来说,它的逻辑地址结构应该是由段号,页号还有页内偏移量组成,那这个地方的业号和业内偏移量,其实就是,分段管理当中的段内地址,进行再拆分的一个结果,那在考试当中需要注意的是,段号的位数,决定了我们啊,一个进程最多可以分几个段,而页号的位数决定了每个段,最大会有多少页,页内偏移量,的位数又决定了页面的大小,和内存块的大小,所以如果一个系统当中,它的地址结构是这样的,并且这个系统是按自己选址的话,那么段号占16位,所以这个系统当中,每个进程最多可以有2的16次方,也就是64K个段,而业号占4位,所以每个段最多会有2的4次方,也就是16页,另外页内偏移量占12位,所以每个页面,每个内存块的大小是2的12次方,也就是4KB这么大,那在断页式管理当中,分段这个过程对用户来说是可见的,程序员在编程的时候,需要显示的给出段号和段内地址,这样两个信息,是把各个段进行分页的,这个过程对用户来说是不可见的,这只是一个系统的行为,系统会把段内地址自动的划分为,段号和段内篇一量这样两个部分,所以对于用户来说他在编程的,时候只需要关心,段号和段内地址这两个信息,而剩下的分页是由操作系统完成的,因此段页是管理的地址结构是二维的,那与此相对的,段式管理当中地质结构也是二维的,而夜式管理当中地质结构是一维的,那与之前咱们介绍的
分页和分段管理当中的思想相同,对进程分段,在分页之后,我们也需要记录各个段,各个页面存放的一个位置,所以系统会为每个进程建立一个段表,进程当中的各个段,会对应段表当中的一个段表项,而每个段表项由段号,呃页表长度和页表存放快号组成,那由于每个物理块的大小是固定的,所以只要知道页表存放的物理块号,其实就可以知道,页表存放的实际的物理地址,到底是多少啊,那比如说,我们要查找0号段对应的页表,那么我们知道,这个页表存放在内存为1号块的地方,也就这个位置是,就可以从这个内存块当中,读出0号段对应的页表,那由于0号段呃长度是7KB,而每个页面大小是4KB,所以它会被分成两个页面,相应的这两个页面,就会依次对应页表当中的一个页表像,每一个页表像记录了每一个页面,存放的呃内存块号到底是多少,所以通过刚才的讲解大家会发现,在段页式管理当中,段表的这个结构,和段式管理当中的段表是不一样的,段式管理当中的段表记录的是段号,还有段的长度还有段的起始,地址这么3个信息,而段页式管理当中记录的是段号,页表长度页表存放快号这么3个信息,也就是后面的这两个信息不太一样,而对于页表来说,段页式管理和分页管理的页表结构,基本上都是相同的,都是记录了页号,到物理快号的一个映射关系,那各个段表项的长度是相等的,所以段号可以是隐行的,各个页表项的长度也是相等的,所以页号也是可以隐行的,那这两点,咱们在之前的小节有详细的介绍过,这就不再展开,那从这个分析当中我们会发现,一个进程只会对应一个段表,但是每个段会对应一个页表,因此一个进程有可能会对应多个页表,再重复一遍一个进程会对应一个段表,但是,一个进程有可能会对应多个页表,那么接下来我们再来看一下啊,怎么实现断印式管理当中的这种逻辑,地址转化为物理地址的这个过程,首先需要知道
知道的是,系统当中,也会有一个断表寄存器这么一个硬件,然后在呃这个进程上处理机运行之前,会从PCB当中读出断表食指,还有断表长度这些信息,然后放到断表寄存器当中,那再进行地址转换的,第一步是需要根据逻辑地址得到段号,页号还有页内偏移量这么三个部分,那第二步,需要把段号和段表长度进行一个对比,检查段号是否越界是否合法,如果越界的话就会抛出一个中段,之后由中段处理程序进,行处理,如果没有越界的话就证明段号合法,就可以继续执行,接下来一步,可以根据段号还有段表食指,来计算出,呃这个段号对应的段表项,在内存当中中的位置,这样的话,就找到了我们想要找的这个段表项,接下来一步需要注意,由于各个段的长度是不一样的,所以各个段呃把它们分页之后,可能分为数量不等的不同的一些页面,比如说有的段长一些,它就可以分为两个页面,有的段短一些只需要用一个页面,所以由于各个段分页之后,页面数量可能不同,因此,这个地方我们也需要对页号的合法性,进行一个检查,看看页号是否已经越界,如果页号啊没有超出页表长度的话,那么就可以继续往下执行,通过这个断表项,我们知道了页表存放的位置,于是就可以从这个位置读出页表,于是可以根据页号来找到,我们想要找到那个页表项,那找到这个页表项之后,我们就知道,这个页面在内存当中存放的位置,所以最后我们可以根据页表像当中,对应的这个内存快号,和页内偏移量进行二进制的拼接,最终形成要访问的物理地址,那最终我们就可以根据这物理地址,进行访存,访问目标内存单元,因此在断页式管理当中,进行地址转换的这个过程,总共需要三次访存,第一次访存是访问内存当中的段表,第二次访存是访问内存当中的页表,第三次访存,才是访问最终的目标内存单元,我们之前也介绍,过在分页和分段这两种管理方式当中,可以用引入快表机构的方式,来减少地址转换过程当中访存的次数,所以,这个地方我们也可以用相同的思路,我们可以引入快表机制,用段号和页号作为块表的,查询的关键字,那如果块表命中的话,我们就可以知道,我们最终想要访问的那个页面,到底是在什么位置,因此只要块表命中,我们就不需要再查询段表和页表了,这样的话我们仅需要一次访存,也就是最终访问目标内存单元,这则,那么这就是断页式管理方式当中,进行地址变换的一个过程,需要着重注意的是,呃这一步就是检查页号是否越界,那这个和,段式存储当中,检查,呃段的地址是否越界是比较类似的,需要检查的本质原因就在于,各个段的长度可能是不相等的,因此需要进行这样一个合法性的检查,好的那么这个小节
我们介绍了段页式管理,在学习了之前的分段,还有分页管理之后,啊这个小节的内容并不难理解,需要注意的是,段页式管理当中逻辑地址结构由段号,页号和页内添一量这么三个部分构成,但是用户在编程的时候,只需要显示的给出段号和段内地址,之后,会由系统自动的把段内地址拆分为,页号和页内偏移量,这么两个部分,因此由于用户只需要提供,段号和段内地址这么两个信息,因此,断页式管理当中地址结构是二维的,那显然分段对于用户来说是可见的,但是分页是操作系统,呃管理的一个行为,对于用户来说不可见,那么在这个小节当中,我们还介绍了段表和页表的结构,还有原理,需要注意的是,段页式管理中的段表,和分段管理当中的段表,呃结构是不太一样的,段页式管理当中段表由段号,页表长度,页表存放地址这么3个信息组成,但是在分段管理当中,由段号段的长度,还有段的起始地址这么3个信息组成,所以呃段表是不太一样的,但是页表的话,和分页存储当中的,页表的结构是相同的,都是由页号,还有页面存放的内存括号来组成,那之后我们介绍了地址变换的过程,那比起分,页和分段的地址变换过程来说,断页式管理需要查先查询断表,之后还需要再查询页表,并且在找到断表项之后,还需要对页表长度,还有页号进行一个对比检查,看看页号是否已经越界,那同学们需要理解这个过程,能够自己写出来它的,地址变换过程到底是什么样的,那最后我们还分析了断页式管理当中,访问一个逻辑地址所需要的访存次数,第一次访存是需要查段表,第二次访存是查页表,第三次访存才是访问目标内存单元,那如果我们引入了快表机构之后,就可以以段号还有,页号作为关键字去查询快表,如果快表命中的话,那么仅需要一次访存,好的,那么以上就是这个小节的全部内容
No.12 虚拟内存的基本概念
各位同学大家好,从这个小节开始,我们会开始学习,虚拟内存相关的一系列知识点,那这个小节,我们会首先介绍,虚拟内存的一些基本概念,那在之前的小节中我们知道,操作系统对内存进行管理,需要实现对内存空间的分配与回收,对内存空间的扩充,那关于分配与回收这个问题,咱们之前介绍了一系列的,传统的内存管理方案,包括基本分页基本分段基本段页式,还有什么固定分区,动态分区等等一系列的存储管理方式,那在这些传统的,存储管理方式的基础上,如果再加上覆盖技术,或者交换技术的话,就可以使内存的利用率啊,进一步的得到提升,能够从逻辑上拓充啊内存的容量,那这个小节我们介绍的虚拟存储技术,其实也是一种,实现内存空间拓充的一个呃一种技术,它比交换技术和覆盖技术,要更先进一些,那在这个小节中
我们会首先介绍,传统的那些存储管理方式的特征,特别是缺点,那在人们发现了局部性原理之后,高速缓存技术又得到了进一步的发展,那虚拟内存,也是基于高速缓存技术的思想啊,提出的一种内存管理方案,那之后,我们会介绍虚拟内存的定义和特征,之后我们还会简单的提一下,虚拟内存技术应该怎么实现,那我们会按照从上至下的顺序,依次讲解,那首先
先来看一下,传统的存储管理方式的特征,特别是缺点,那所谓的传统存储管理方式啊,指的是咱们之前介绍的这一系列的啊,像基本分页基本分段基本段也是,还有什么固定分区动态分区,单一连续分配,这一系列的存储管理方案,那如果系统使用的是这些存储,管理方案,那么很多暂时用不到的数据,其实也会长期的占有内存,导致内存的利用率不高,所以传统的这种啊存储管理方式,有两个很明显的特征,一个叫做一次性,就是指,作业必须一次性的全部装入内存之后,才可以开始运行,那由于这样的规定就导致了两个问题,一当作业很大的时候,不能把全部的作业都装入内存,就导致大作业无法运行,那这个就类似于咱们之前提到过的GTA,那个游戏本来需要60G的内存,那如果说,采用的是传统的这种存储管理方,式的话那,4GB的电脑是不可能运行,60G大小的游戏的,所以这是呃它造成的第一个问题,作业大小超出内存的总容量的时候,那这个作业肯定是无法运行的,第二个问题,当大量的作业要求运行的时候,那这些作业的,大小总和,可能已经超出了内存的总容量,那这样的话,内存就无法容纳所有的作业,是所有的作业有要求,必须一次性全部装入内存,才可以开始运行,因此,其实内存当中是不可能支持这些,所有的,大量的作业都同时并发运行的,这样的话就,导致了多道程序的并发度下降,所以这是,传统存储管理方式的第一个特征,叫做一次性,第二个特征叫做驻留性,就指一个作业一旦放入内存之后,会一直驻留在内存当中,直到作业运行结束,但实际上可能在一个时间段内,我们只需要访问,一个作业当中的一小部分的数据,这个作业就可以正常开始运行了,比如说咱们在玩GTA那个游戏的时候,如果说此时在呃游戏的a场景,那么b场景的资源,就暂时不需要被加载到内存当中,我们只需要在,内存当中放入a场景相关的资源,其实就可以保证这个游戏的正常,运行了但是,如果说采用的是,传统的这种存储管理方式的话,那么,不管是a场景还是b场景的这些数据,都要求一直驻留在内存当中,论此时是否需要这些数据,因此这样的话,就导致了,内存当中,实际上是驻留了大量的,暂时用不到的数据,从而导致了内存资源的浪费,那显然传统的存储管理方式,其实存在很多缺点,那这些缺点,其实都可以用虚拟存储技术来解决,那虚拟存储技术的提出,其实是基于著名的局部性原理,那局部性原理咱们在直
前的课程当中也有简单的提到过,分为时间局部性和空间局部性,时间局部性指的是呃,如果一个程序在执行的过程当中,访问到了某一条指令或者某一个数据,那么此时访问到的这条指令或者数据,在不久之后有可能会被再次访问到,因为程序当中存在着大量的循环,比如说在这个程序当中,由于存在这样一个循环,所以循环当中的这些代码指令,有可能会很频繁的,一次又一次的被访问,那循环当中访问到的这些数据,比如说变量i,也会被频繁的一次又一次的访问,所以这是时间局部性,那空间局部性指的是,如果说啊,此时,访问了内存当中的某个存储单元的话,那么不久之后,这个存储单元附近的那些存储单元,有可能会被访问,那导致空间局部性的原因,是因为我们的程序当中,很多数据其实是连续存放的,比如说啊数组a的这100个数组元素,其实在内存当中是连续存放的,并且在程序当中访问数组a的时候,经常是需要连续的访问,数组a当中的各个各个数组项的,而这些数组项,在内存当中又是连续存放的,因此,只要访问到了其中的某一个存储单元,那么就很有可能在不久之后,访问,与这个存储单元相邻的那些存储单元,另一方面,其实程序当中的这些指令,在内存当中是连续的存放的,比如说这个循环当中的AI,等于i这条代码对应的指令,还有i加加这条代码,对应的那一系列的指令,在内存当中都是连续存放的,那由于我们的程序是顺序执行的,所以只要我们执行了第一条指令,那么就意味着与他,相邻的那个存储单元,当中存放的第二条指令,也很有可能在不久之后会被,接着访问,所以这是造成空间局部性的一个原因,基于局部性原理
我们可以让程序在装入的时候,只是把程序当中,很快就会使用到的部分,先放入到更高速的内存当中,然后暂时使用不到的部分,暂时先留在外存,就可以开始让程序执行了,如果程序执行的过程当中,想要访问的信息,暂时还不在内存的时候,就需要由操作系统负责把,所需要的那些信息,再从外存调到内存当中,然后再继续执行程序,另外如果说内存的空间已经满了,内存空间不够的话,那么操作系统还需要负责把内存当中,暂时用不到的那些信息,数据换到外存当中,所以如果操作系统用这样的方式,来管理内存的话,那么其实在用户看来,内存的容量,是要比实际的内存容量大得多的,那这就是虚拟内存技术,虚拟内存,也是操作系统虚拟性的一个体现,所谓的虚拟性,指的是,内存的实际物理容量其实是没有变的,只不过是通过操作系统的一系列的,呃虚拟技术,实现了从逻辑上扩充了内存的容量,那在采用了虚拟内存技术之后,系统表现出了这样的几个主要特征,第一个特征叫做多次性,就是指在作业运行的时候,不需要一次性的全部装入内存,而是允许一个作业的数据,被分为多次掉入内存,第二个特性叫兑换性,就指在作业运行,的时候不需要一直,让作业的所有数据都长驻内存,而是允许在作业运行的过程当中,把作业的一些数据换入或者换出内存,那多次性和兑换性,刚好就对应了,传统的内存管理方案当中的一次性,和注流性,第三个的特性叫做虚拟性,就是指,虽然说内存的实际物理容量没变,但是在用户看来,从逻辑上是拓充了这个内存的容量的,可见在采用了虚拟内存技术之后,对内存的利用率,还有系统的性能,都是会有一定的提升的,那么怎么实现虚拟内存技术呢
首先我们需要明确的是,既然虚拟内存技术,允许一个作业分为多次掉入内存的话,那么如果说我们采用的是连,续分配的方式,那么一个作业如果先掉入了一部分,那后一部分想要在掉入的时候,还需要给这个作业,分配,与之前给它分配的那个内存空间,相连续的一部分内存空间,也就是说采用连续分配的话,那么每次给作业分配的内存空间,都需要保证是都是连续的,所以这样实现起来其实很不方便,因此虚拟内存技术,需要建立在,离散分配的内存管理方式的基础之上,那之前咱们学了几种传统的,离散分配的存储管理,也就是基本分页基本分段,还有基本断页式,那在这些存储管理方式的基础之上,如果在应用虚拟内存技术的话,那么就形成了与他们相对应的,请求分页,请求分段还有请求断页式存储,管理那这种传统的存储管理方式,还有虚拟内存的存储管理方式,最主要的区别就在于,在虚拟内存技术当中,如果说在程序执行的时候,发现我们此时要访问的信息,并没有在内存当中,那么操作系统需要负责,把啊所需要的信息从外存,调入内存,然后继续执行程序,另外如果内存空间不够的话,那操作系统还需要负责把,内存当中暂时用不到的信息,换出外存,所以为了满足这两个全新的需求,操作系统需要在基本的这几种,存储管理方式的基础上,再增加两个主要的功能,第一个就是请求调页,或者请求调段功能,所以请求调页就是指,在请求分页存储管理当中,如果说我们所需要的页面,暂时还不在内存当中,那么操作系统需要负责,把这个页面从外存调入内存,并且完善一系列的处理,那第二个需要新增的主要功能,是页面置换功能,或者是断置换功能,当内存空间不够的时候,操作系统需要通过这个置换功能,把暂时用不到的分页,或者暂时用不到的分段,先换出外存当中,所以这就是实现虚拟内存技术的时候,我们需要最重点关注的两个功能,一个是请求调页功能,一个是页面置换功能,当然这个地方呢,请求调页和页面置换,对应的是请求分页存储管理方式,如果是请求分段存储管理方式的话,那么操作系统,需要提供的就是请求调断,还有断置换的功能,好的那么这个小节
当中我们介绍了,虚拟内存管理的一系列基本概念,那传统的存处管理方式,存在着一次性还有驻留性,这样两个比较明显的特征,那这两个特征也导致了,传统管理方式存在了一系列的缺点,不过,基于局部性原理提出的虚拟内存技术,其实可以解决,传统存处管理方式当中的这些缺点的,局部性原理分为时间局部性,还有空间局部性啊,这两个知识点大家需要理解,在选择题当中还是,很有可能进行考察的,那基于局部性原理,人们提出了各种各样的高速缓存技术,他们的核心思想就是,需要把频繁使用的数据,放到更高速的存储器上,但是暂时用不到的或者使用频率低的,可以放在更低速的那些存储器上,虚拟内存技术其实也是局部性原理,还有高速缓存技术的一个,进一步的应用和拓展,那在采取用了虚拟内存技术之后,系统体现出了多次性,兑换性还有虚拟性这些全新的特征,那多次性和兑换性,与传统存处管理方式当中的一次性,还有驻流性,刚好是一一对应的,大家需要对比着来理解和记忆,那最后,我们探讨了怎么实现虚拟内存技术,我们重点需要关注的是请求调页功能,还有页面置换功能,不过这些功能,我们会在之后的小节当中,进行更详细的学习,那虚拟内存的实现主要分为请求分页,请求分段,还有请求断页式存储管理,这样3种方式,那之后我们会重点介,绍请求分页存储管理方式,好的,那么以上就是这个小节的全部内容,
No.13 请求分页管理方式
各位同学大家好,在这个小节中,我们会学习请求分页管理方式,相关的一系列知识点,那么通过上个小节的学习我们知道,请求分页管理方式,是在基本分页管理方式的,基础上进行扩展,从而实现的一种虚拟内存管理技术,那相比于基本分页存储管理,操作系统,还需要新增两个最主要的功能,第一个功能就是请求掉页的功能,系统需要判断,一个页面是否已经掉入内存,如果说还没有掉入内存,也就是页面缺失的话,那么还需要将,页面从外存掉到内存当中,那这是请求掉页功能,第二个需要提供的功能是,页面置换功能,就是当内存暂时不够用的时候,需要决定把哪些页面换出到外存,那针对于这两个功能如何实现,我们会介绍在请求分页管理方式当中,页表机制,与基本分页存储管理方式当中,有哪些呃相同和不同的地方,另外为了实现请求调页的功能,那呃请求分页管理系统当中引入了,缺页中断机构,最后我们会介绍在这种管理方式当中,啊地质变化到底是什么样一个过程,那在学习这个小节的时候,需要注意和基本分页存储管理方式,进行一个对比,那首先我们来看一下,这种管理方式,和基本分页存储管理方式,的页表机制有哪些相同和不同的地方
那我们还是从如何实现,页页面置换,和请求调页这两个功能的角度出发,来分析页表机制应该怎,么设计首先,与基本分页存储管理相比,为了实现请求调页,那么操作系统肯定需要知道每个页面,是否已经掉入内存,如果这个页面还没有掉入的话,那么也需要知道这个页面在外存当中,存放的位置,所以为了知道这些信息,那么肯定需要把这些信息,记录在某种数据结构当中,那页表其实就是一个很好的地方,另外为了实现页面置换功能,那么操作系统肯定需要通过某种规则,来决定,到底是把哪个页面啊换出到外存,所以,我们需要记录每个页面的一些指标,然后操作系统根据这个指标,来决定到底换出哪一页,另外呢如果说一个页面,在内存当中没有被修改过,那么这个页面其实换出外存的时候呃,不用浪费时间再写回外存,因为它没有修改过,所以外存当中保存的那个副本,其实和内存,当中的这个数据是一模一样的,那只有页面修改过的时候,才需要把它换到外存当中呃,把以前旧的那个数据覆盖,所以,操作系统也需要记录各个页面是否被,修改这样的信息,因此相比于基本分页的页表来说,请求分页存储管理的页表,增加了这样的4个字段,一个是状态位,状态位就是用于表示,此时,这个页面到底是不是已经掉入内存了,比如说在这个表当中,0号页面的状态位是0,表示0号页面暂时还没有掉入内存,那1号页面的状态位是一,表示1号页面此时已经在内存当中了,第二个新增的数据是访,问字段操作系统在置换页面的时候,可以根据访问字段的这些数据,来决定到底要换出哪一个页面,所以我们可以在访问字段当中,记录每个页面最近被访问过几次,我们可以选择把,访问次数更少的那些页面换出外存,或者我们也可以在访问字段当中,记录我们上一次访问这个,页面的时间,那这样的话,我们可以实现,优先的换出,啊很久没有使用的页面这样的事情,所以这是访问自断的功能,那第三个新增的数据是修改位,就是用来标记,这个页面在掉入内存之后,是否被修改过,因为没有被修改过的页面是,不需要再写回外存的,那不写回外存的话就可以节省时间,第四个需要增加的数据就是呃,各个页面在外存当中存放的位置,那这是请求分页存储管理方式当中的,页表新增的4个字段
那在有的地方,也会把这个页表称为请求页表,然后这个页表称,本页表或者简称页表,那这是请求分页存储管理当中,页表机制产生的一些变化,新增的一些东西,那这也是实现请求调页,和页面置换的一个,数据结构的基础,那为了实现请求调页功能,系统当中需要引入区域中断机构,我们直接来结合一个例子来,理解区域中段机构工作的一个流程,假设在一个请求分页的系统当中,要访问一个逻辑地址,页号为0页内篇译量为1024,那么为了访问这个逻辑,地址需要查询页表,那缺页中断机构会根据对应的页表项,来判断,此时这个页面是否已经在内存当中,如果说没有在内存当中,也就是这个状态位为0的话,那么会产生一个缺页中断信号,之后操作系统的缺液中断处理程序,会负责处理这个中断,那由于中断处理的过程需要IO操作,把页面从外存掉入内存,所以在等待IO,操作完成的这个过程当中,之前发生缺液的这个进程应该被阻塞,放入到阻塞队列当中,只有掉液的事情完成之后,才把它再唤醒,重新放回旧绪队列,那通过这个页表像,就可以知道这个页面在外存当中,存放在什么地方,那如果说此时内存当中有空弦的快,比如说a号快空弦的话,那就可以把这个空弦快,分配给啊此时缺页的这个进程,再把目标页面从外存放到内存当中,那相应的也需要修改页表像当中,对应的一些数据,那这是第一种情况,就是有空弦的内存快的情况,第二种情况,如果说此时内存中没有空闲快的话,那么需要由页面置换算法,通过某种规则来选择要淘汰一个页面,比如说,页面置换算法选中了要淘汰2号页面,那由于2号页面的内容是被修改过的,所以2号页面的内容,需要从内存再写回外存,把外存当中的那个旧数据给覆盖掉,那这样的话,2号页面以前占有的c号块,就可以空出来让0号页面使用了,于是可以把0号页面从外存,掉入内存当中的,c号块那相应的我们也需要把,换出外存的页面,还有换入内存的页面,相应的那些数据给更改,那这是第二种情况,就是内存当中没有空闲块的时候,需要用页面置换算法淘汰一个页面,那确页中断的发
发生肯定和当前执行的指令是有关的,由于这个指令,想要访问某一个逻辑地址,而系统又发现,这个逻辑地址对应的页面,还没有调入内存,因此才发生了缺页中断,那由于它和当前执行的指令有关,因此缺页中断是属于内中断的,还记得咱们之前讲的内中断,和外中断的分类吗,内中断可以分为陷阱,故障还有终止这样3种类型,其中故障这种内中断类型,是指有可能被故障处理程序修复的,比如说缺液中断这种异常的情况,是有可能被操作系统修复的,因此它是属于故障这种分类,另外呢我们需要注意的是,一条指令在执行的过程当中,有可能会产生多次缺页中断,因为一条指令当中可能会访问,多个内存单元,比如说把逻辑地址a当中的数据,复制到逻辑地址,地址b当中,那如果说这两个逻辑地址,属于不同的页面,并且这两个页面都没有掉入内存的话,那么在执行这条指令的时候,就有可能会产生两次中断,通过之前的讲解我们会发现,引入了缺液中断机构之后,系统才能实现啊请求调验这样的事情,那接下来我们再来看一下
请求分页存储管理,与基本分页存储管理相比,在地址变换的时候,需要再多做一些什么事情,第一个事情,在查找到页面对应的页表项的时候,一定是需要,对这个页面是否在内存,这个状态进行一个判断,第二个事情在地址变换的过程当中,如果说我们发现此时选好访问的页面,暂时没有掉入内存,但是此时内存当中又没有空闲的,内存快的时候,那么在这个地址变换的过程当中,也需要进行页面置换的工作,换出某些页面来腾出内存空间,第三个,与基本分页存储管理不同的就是啊,当页面调入或者调出,或者页面被访问的时候,需要对与他对应的这些页表象,进行一个数据的修改,所以我们在理解和记忆,请求分页存储管理当中,一直变换过程的时候,需要重点关注这3件事情,需要在什么时候进行,那与基本分页存储管理相同请求分
业存储管理啊,在逻辑地址,变化为物理地址的过程当中,需要做的第一件事情,同样是要检查业号的合法性,看一下业号是否越界,如果页号没有越界的话,就会查询,此时在快表当中,有没有这个页号对应的页表项,那如果快表命中,就可以直接得到最终的物理地址,如果快表没有命中的话,就需要查询内存当中的漫表,那在找到对应的页表像之后,需要检查此时这个页面是否已经在,内存当中,如果说这个页面,此时没有在内存当中的话,那缺页,中断机构会产生一个缺页中断的信号,之后就会有操作,系统的缺页中断处理程序进行处理,包括掉页,还有页面置换那一系列的事情,那当然当页面掉入之后,也需要修改,这个页表相对应的一些数据,那这个地方注意一个细节,在请求分页管理方式当中,如果说能够在快表当中,找到某一个页面对应的页表像,那么就说明,这个页面此时肯定是在内存当中的,如果一个页面被换出了外存的话,那么快表像当中对应的这些页表像,也应该被删除,所以只要块表命中,那么就可以直接根据这个内存快号,还有页内篇移量,得到最终的物理地址了,这个页面肯定是在内存当中的,那这个地方,并没有像基本分页管理方式当中那样,一步一步很仔细的分析,那其实大家只需要关注,请求分页管理方式,与基本分页管理方式相比,啊不同的这些步骤就可以了,那其实课本当中给出了一个很完整的,请求分页管理方式当中,呃地址变换的一个留审图,大家需要重点关注
录的是这两个红框部分当中的内容,这些内容就是请求分页管理方式,与基本分页管理方式相比,增加的一些步骤和内容,那这根据这个图,补充几个大家可能注意不到的细节,第一个地方,通过这个图,特别是这个步骤大家有可能会发现,似乎只要访问了某一个页面,那么这个页面相关的修改位,是不是就需要修改呢,其实并不是,只有执行写指令的时候,才会改变这个页面的内容,如果说执行的是读指令,那么就其实不需要修改这个,页面对应的修改位,并且一般来说,在访问了某一个页面之后,只需要把这个页面,在快表当中对应的表象,的那些数据修改了就可以了,那只有呃,他所对应的那些表象,要从快表当中删除的时候,才需要把,这些数据从快表再复制回慢表当中,那采取这样的策略的话,就可以减少访问内存当中慢表的次数,可以提升系统的性能,第二个需要注意的地方是,在产生了缺液中断之后,缺液中断处理程序也会保存CPU现场,那这个地方,其实和普通的中断处理是一样的,在中断处理的时候,需要保存CPU的现场,然后让这个进程暂时进入阻塞台,那只有这个进程在,重新回处理及运行的时候,才需要再恢复它的CPU现场,三个需要注意的地方是,内存满的时候需要选择一个页面换出,那到底换出哪个页面,这是页面置换算法要解决的问题,也是咱们下个小节当中会详,细介绍的内容,第四个需要注意的点是,如果我们要把页面写回外存,或者要把页面从外存调入内存的话,那么需要启动IO硬件,所以其实把页面换入换出的工作,都是需要进行慢速的IO操作的,因此如果换入换出操作太频繁的话,那系统会有,很多的时间是在等待慢速的IO,操作完成的,因此页面的换入换出不应该太频繁,第五个需要注意的地方,当我们把一个页面从外存调入内存,之后需要修改内存当中的页表,但是其实,我们同时也需要把这个页表像,复制到块表当中,所以由于新调入的页面,在块表当中是有对应的页表象的,因此在访问一个逻辑地址的时候,如果发生了缺页,那么地址变换的步骤应该是这样的,第一步首先是查询快表,如果快表没有命中的话,才会查询内存当中的慢表,然后通过慢表会发现,此时页面并没有掉入内存当中,之后系统会进行调页相关的操作,那在页面调入之后,不仅要修改内存当中的慢表,也需要把这个页表像,同时加入到快表当中,于是之后,可以直接从快表当中,得到这个页面存放的位置,而不需要再查询慢表,那这是地址变换过程当中,大家需要注意的几个点,那其他的流程其实并不难理解,右半部分的这些流程其实和,基本分页存储管理方式进行,地址变换的呃这个过程是大同小异的,只不过是增加了,修改这个页表相相应的内容,这这样一个步骤,左半部分是新增的一系列处理,那要做的无非也就两件事,第一件事就是当我们发现呃,所要访问的页面没有在内存,当中的时候,需要把页面从外存调入内存,那如果说内存此时已经满了,那需要做页面置换的工作,那当调页还有页面置换这,些工作完成之后,也需要对,页表还有块表当中的,对应的一些数据进行修改,所以其实只要理解了,我们应该在什么时候,请求调页,又应该在什么时候进行页面置换,当调页和页面置换完成之后,又需要对哪些数据结构进行修改,只要知道这3个事情,那就可以掌握,请求分页管理方式,地址变换的这些精髓了,好的那么这个小节
我们介绍请求分页管理方式,与基本分页管理方式相比,请求分页管理方式在页表当中增加了,状态位访问字段,修改位还有外存地址这样几个数据,那大家需要理解,这几个数据分别有什么作用,那之后我们介绍了雀跃中断机构,那在引入了雀跃中断机构之后,如果一个页面暂时没有掉入内存,那就会产生一个雀跃中断信号,然后之后,系统会对这个雀跃中断,进行一系列的处理,另外呢大家需要注意的是,缺页中断它是属于内中断,它和当前执行的指令有关,并且一条指令在执行的过程当中,有可能会访问到多个内存单元,而这些内存单元,呃有可能是在不同的页面当中的,因此一条指令执行的过程当中,有可能会产生多次缺页中断,那最后我们介绍了呃,请求分页管理方式的地址变换机构,其实我们只需要重点关注,与基本分页方式不同的那些地方,第一在找到页表像的时候,需要检查页面是否在内存当中,由此来判断此时是不是需要请求调页,那在调页的过程当中,如果发现,此时内存当中已经没有空闲话,那我们还需要进行换出页面的操作,另外在调入和换出了一些页面之后,我们也需要修改,与这些页面对应的那些页表,像那除了这些步骤以外,其他的其实和基本分页存储管理当中,地址变换的过程,并没有太大的区别,那这个小节的内容在于理解,不需要死记硬背,大家还需要通过,课后习题进行进一步的巩固和理解,好的,那么以上就是这个小节的全部内容
No.14 页面置换算法
各位同学大家好,在这个小节中,我们会学习请求分页存储管理当中,很重要的一个知识点考点啊,页面置换算法,那么通过之前的学习我们知道,在请求分页存储管理当中,如果说内存空间不够的话,那么操作系统会负责啊,把内存当中暂时用不到的那些信息,先换出外存,那页面置换算法其实就是用于选择,到底要把哪个页面换出外存,那通过之前的学习我们知道,页面的换入换出,其实是需要启动磁盘的IO的,因此它是会造成比较大的呃时间开销,所以一个好的页面置换算法,应该尽可能的追求更少的缺页率,也就是让换入换出的次数尽可能的少,那这个小节中,我们会介绍考试中要求我们掌握的,5种页面置换算法,分别是最佳置换,先进先出最最近最久未使用,还有时钟置换改进型,的时钟置换这样5种,那除了注意他们的中文名字之外,大家也需要能够区分,他们的英文缩写到底分别是什么,那我们按从上至下的顺序依次介绍,首先来看
那什么是最佳置换算法,其实最佳置换算法的思想很简单,由于置换算法需要追求呃,尽可能少的确页率,那为了追求最低的确页率呃,最佳置换算法在每次淘汰页面的时候,选择的都是那些,以后永远不会被使用到的页面,或者啊在之后最长的时间内,不可能再被访问的页面,那我们直接来看一个例子来加深理解,假设,系统为一个进程分配了三个内存块,然后这个进程执行的过程当中,会依次需要访问到这些页面,那刚开始进程需要访问的是7号页面,那由于刚开始,未进程分配的这三个内存块都是空的,所以我们可以选择把,7号页面放入内存块一当中,第二个要访问到的页面是0号页,由于此时依然还有空闲的内存块,所以我们可以把0号页,放入内存块2当中,第三个要访问的是1号页面呃,同样的此时还剩一个空闲的内存块,所以1号页面可以放到内存块3当中,第四个我们需要访问到的是2号页面,但是由于此时给这个进程分配的,三个内存块都已经,占满了,所以我们必须用页面置换算法,选择淘汰其中的某一个页面,把那个页面先换出外存,那根据最佳置换算法的规则,我们要选择的是呃,在今后最长时间内,不会被使用到的页面,所以其实我们在手动做题的时候,可以看一下它的这个序列,我们从当前访问的这个页号开始,往后寻找,看一下此时在内存当中的啊,零一击,这三个页面出现的顺序到底是什么,那最后一个出现的序号,肯定就是在之后最长时间内,不会再被访问的页面,所以从这往后看,0号页面是最先出现的,那3号页面不属于零一,7当中的任何一个,所以跳过0号页面之后会再次出现,然后4号也不属于零一7,之后又会出现2号页面3号页面0号页面,然后一直到这个位置,我们发现1号页面也开始出现了,所以零一7这三个页面当中,0号和1号会在之后啊依次被使用,但是7号页面是在之后最长的时间内,不会再被访问到的页面,因此我们会选择淘汰7号页面,然后让2号页面,放入到7号页面原先占有的内存块,也就是内存块一当中,因此2号页面置放在这个位置的,那接下来要访问的0号页面,已经在内存当中了,所以此时不会发生缺页,可以正常的访问,再之后访问3号页面,也会发现,此时3号页面并没有在内存当中,所以我们依然需要用这个置换算法,选择淘汰一个页面,那么那和刚才一样,我们从这个位置开始往后寻找,看一下此时内存当中存放的,201这三个页面,呃出现的先后顺序,那我们会发现201当中,0号页面是最先出现的啊,之后2号页面紧接着出现,那么1号页,面就是最后一个出现的,因此 1号页面是在今后最长时间内,不会再被访问的页面,所以我们会选择,把201这三个页面当中的1号页面给淘汰,先换出外存,然后3号页面再换入,1号页面以前占有的那个内存块,也就是内存块3当中,所以3号页面是放在这个地方的,对于之后的这些页面序号的访问,我们就不再细细的分析了,大家可以自己尝试着去,完善一下这个表,那最终我们会发现啊,整个访问这些页面的过程当中,缺页中断发生了9次,也就这打勾的这些位置,发生了缺页中断,但是页面置换只发生了6次,所以大家一定需要注意,缺液中断之后未必发生页面置换,只有内存快已经都满了的时候,才需要页面置换,因此在刚开始访问机零一,这三个页面的时候,虽然他们都没有在内存当中,但是由于刚开始内存有空闲的内存块,所以啊虽然发生了缺液中断,虽然会发生掉液,但是并不会发生页面置换这件事情,只有所有的内存块都已经占满了之后,呃再发生缺页的话,那才需要进行页面置换这件事情,因此缺页中断总共发生了9次,但是页面置换只发生了6次,前面的3次呃只是发生了缺页,但是并没有页面置换,那缺页率的计算也很简单,我们只需要把缺页中段发生的次数,再除以我们总共访问了多少次的页面,就可以得到缺页率是45%,那这是最佳置换算法,那其实,最佳置换算法执行的前提条,件是我们必须要知道,之后会依次,访问的页面序列到底是哪些,不过在实际应用当
中只有在进程执行的过程当中,才能一步一步的知道,接下来会访问到的到底是哪一个页面,所以,操作系统其实根本不可能提前预判,各个页面的访问序列,所以最佳置换算法它只是一种,理想化的算法,在实际应用当中是无法实现的,那接下来我们再来看第二种,先进先出置换算法
这种算法的思想很简单,每次选择淘汰的页面,是最早进入内存的页面,所以在具体实现的时候,呃可以把掉入内存的这些页面,根据掉入的先后顺序来排成一个对列,当系统发现需要换出一个页面的时候,只需要把对头的那个页面淘汰,就可以了,那需要注意的是,这个对列有一个最大长度的限制,那这个最大长度,取决于,系统为进程分配了多少个内存块,那我们还是来看一个例子,假设,一个系统为进程分配了3个内存块,然后会按照这样的顺序,依次访问各个页面,那首先访问的是3号页面,此时内存块一是空间的,所以,可以把3号页面放到内存块一当中,并且把3号页面放到,我们之前提到的这个对列的对头,第二个页面是2号页面,此时也有内存块空间,所以2号页面放到内存块2当中,然后再把,2号页面放到这个对列的对位,也就是把它接在3号页面之,后的这个位置,那同样的1号页面此时也有内存块,所以它放在内存块啊3当中,并且把1号页面放到这个对列的对位,接下来访问到第四个页面的时候,此时要访问的是0号页面,但是由于此时所有的内存,块都已经占满了,所以必须选择淘汰其中的某一个页面,那么根据系统维持的这个对列,可以知道,3号页面进入内存的时间是最早的,所以会选择淘汰3号页面,然后把3号页面占有的这个内存块1,分配给0号页面,相应的0号页面放入内存之后,也需要把它插到这个对列的对位,那接下来,如果还要再访问3号页面的话,同样的,是需要把这个对头的页面给淘汰掉,所以2号页面会换出外存,然后3号页面,放到2号页面以前占有的内存块2当中,并且会把3号页面,放到这个对列的对位,那以此类推,那剩下的这个过程就不再细细分析了,大家可以自己再去尝动手尝试一下,那整个过程下来会发现,如果给这个进程,分配了3个内存块的话,那么缺页次数总共是123456789缺页了9次,那我们再把这个题目的调节
改一下如果说,给这个进程分配的是四个内存块的话,那按照我们之前分析的这种方法,最终会得到这样一系列的结果,大家也可以自己动手尝试分析,这整个过程,不过这个地方啊我们想强调的是,当为这个进程,分配了4个内存块的时候,虽然说页,面的访问序列依然是啊这样一个序列,但是整个过程下来,缺页次数总共发生了10次,大家可以数一下,但是之前,本来改给进程分配的内存块只有3个,但是3个内存块的时候,缺页次数反而更少,只发生了9次,那其实乍一想来,为一个进程分配的内存块越多,那这个进程的缺液次数应该,越少才对啊,所以像这个地方我们发现的这种现象,就是为进程分配物理块增大的时候,缺液次数不增防减的,这种现象就称作为贝拉迪异常,那,在我们要学习的所有的这些算法当中,只有先进先出算法会产生这种,贝拉迪异常,所以,虽然先进先出算法实现起来很简单,但是先进先出的这种规则,其实,并没有考虑到进程实际运行时候的,一些规律,因为先进入内存的页面,其实在之后也有可能会被经常访问到,所以只是简单粗暴的,让先进入的页面淘汰的话,那显然这是不太科学的,所以先进先出置换算法的算法,性能是很差的,那接下来我们在
看第三个最近最久未使用置换算法,呃英文缩写是LRU,大家也需要记住它的这个英文缩写,很多题目出题的时候,就直接用这样LRU,来表示这个置换算法,那这个算法的规则就像它的名字一样,就是要选择淘汰最近,最久没有使用的页面,所以为了实现这件事,我们可以在每个页面的页,表象当中的访问字段这,记录呃这个页,面自从上一次被访问开始,到现在为止所经历的时间t,那我们需要淘汰一个页面的时候,只需要选择这个t值最大的,也就是,最久没有被访问到的那个页面,进行淘汰就可以了,那我们依然还是结合一个例子,如果一个系统,为京城分配了4个内存块,然后有这样的一系列的页面访问序列,那首先要访问的是1号页,此时有内存块空闲,所以1号页放到内存块一当中,然后第二个访问8号页面,也可以直接放到空闲的内存块2当中,呃以此类推访问1号页面,由于此时1号页已经在内存中了,所以呃不会发生缺页,之后访问的7号8号2号,所有的这些都不会发生页面置换,因为此时呃一直都会有空闲的内存块,那一直到后面访问到,这个3号页面的时候,由于此时,给这个进程分配的4个内存块,都已经用完了,所以必须选择淘汰其中的某个页面,如果我们在手动做题的时候,可以从这个页号开始,逆向的往前检查,此时在内存当中拥有的1872这几个页号,啊从逆向扫描来看,出现的先后顺序是什么样的,那最后一个出现的页号,那肯定就是最近,最久没有使用的页面了,所以从这往前看,8号页面首先出现之后出现了1号页面,再之后出现了2号页面,所以7号页面,即使是这四个页面当中,最近最久没有被使用到的页面,因此会选择把7号页面淘汰,然后3号页就会放入到以前7号页,占用的内存快,3当中同样的在之,后的这一系列访问当中,都不会发生缺页,一直到访问到7号页的时候,呃又发生了一次缺页,并且需要选择淘汰一个页面,那和之前一样,我们从这个地方开始,逆向的往前检查,看一下这几个页号出现的,顺序分别是什么样的,那首先1号页是最先出现的,再往前那3号页出现了,再往前是2号页出现了,所以8号页是这几个页面当中,最近最久没有被使用到的页面,因此会选择淘汰8号页,然后把7号页放入,8号页以前占用的内存块2当中,那最近最久未使用置换算法,在实际的应用当中啊,实际上是需要专门的硬件的支持的,所以这个算法虽然性能很好,但是实现起来会很困难并且开销很大,那在我们学习的这几个算法当中,最近最久未使用这个算法的性能,是最接近最佳置换算法的,那接下来我们再来看第4种始终,
置换算法,之前我们学到的这几种算法当中,最佳置换算法性能是最好的,但是无法实现先进先出算法,虽然实现简单但是算法的性能很差,并且也会出现贝拉迪异常,那最近最久未使用置换算法,虽然性能也很好,但是实现起来开销会比较大,所以之前提到的那些算法啊,都不能做到,算法效果还有实际开销的一个平衡,因此人们就提出了时钟置换算法,它是一种性能和开销比较均衡的算法,又称为clock算法或者叫最近备用算法,英文缩写是NRU那,在考试中,我们需要掌握两种时钟置换算法,分别是简单的啊时钟置换算法,还有改进型的时钟置换算法,那我们先来看简单的这种算法,首先,我们要为每个页面设置一个访问位,访问位为一的时候,就表示这个页面最近被访问过,访问位为0的时候,表示这个页面最近没有被访问过,因此如果说访问了某个页面的话,那需要把这个页面的访问位变为一,那内存中的这些页面,需要通过链接指针的方式,把它们链接成一个循环对列,当需要淘汰某一个页面的时候,啊需要扫描这个循环队列,找到一个最近没有被访问过的页面,也就是访问位为0的页面,但是在扫描的过程中,需要把访问位为一的这些页面的,访问位再重新置为0,所以,这个算法有可能会经过两轮的扫描,如果说所有的页面访问位都是一的话,那第一轮扫描这个循环堆列,就并不会找到任何一个访问位为0的,页面只不过在第一轮扫描当中,会把所有的页面的访问位都置为0,所以在第二轮扫描的时候,就肯定可以找到一个,访问位为0的页面,所以这个算法在淘汰一个页面的时候,最多会经历两轮的扫描,那光看这个文字的描述,其实还是很抽象的,我们直接来看一个例子,这一个系统为进程分配了5个内存块,然后对各个页面号的引用,是按照这样的顺序进行的,那刚开始由于有5个空闲的内存块,所以前5个访问的这个页号,13425都可以顺利的放入内存当中,只有在访问到6号页的时候,才需要考虑淘汰某个页面,那么在内存当中的13425这几个页面,会通过链接指针的方式,链接成一个这样的循环对列,那由于接下来要访问6号页面,但是呃5个内存块都已经满了,所以需要用clock算法,来选择淘汰其中的某一个页面,于是,会从这个循环对列的对手开始扫描,尝试找到一个访问位为0的页面,并且被扫描过的页面需要把访问位,一改为0,所以在经过第一轮的扫描之后,所有的这些页面的访问位都,由1至为了0,那在进行第二轮扫描的时候,1号页面的访问位为0,所以会选择淘汰1号页面,于是 6号页,会装入到,1号页以前占有的这个内存块当中,并且6号页的访问位会被置为一,然后这个扫描的指针指向下一个页面,那接下来的访问当中,会依次访问到3号和4号页面,那在访问了3号页面之后,3号页的访问位需要由0变为一,同样的在访问了4号页面的时候,呃需要把4号页的访问位由0变为1,在之后需要访问7号页,由于此时7号页没有在内存中,所以需要选择淘汰其中的某一个页面,然后把7号页放到内存中,那同样的,需要从此时扫描到的这个位置,依次的扫描,找到第一个访问位为0的页面,并且扫描过的那些页面的,呃这个访问位需要由一变为0,所以3号和4号在扫描过后,访问位会变为0,那在扫描到2号页面的时候,发现2号页面的访问位比本来就是0了,因此会选择淘汰2号页面,然后让7号页面放到这个位置,访问位置为一,然后这个扫描的指针,再指向下一个页面,的位置,那可能通过这个动画会更容易理解,时钟置换算法的一个运行的过程,并且通过刚才的这个例子,大家会发现,这个扫描的过程有点像,一个时钟的那个时针,在不断的转圈的一个过程,所以为什么这个,算法要叫做时钟置换算法,它其实是一个很形象的比喻,那其实经过刚才的分析,我们也很容易理解为什么它,还称作最近未用算法,因为我们会为各个,页面设置一个访问位,访问位为一的时候表示最近用过,访问位为0的时候表示最近没有用过,但是我们在选择淘汰一个页面的时候,是选择那种最近没有被访问过,也就是访问位为0的页面,因此,这种算法也可以称作为最近未用算法,那接下来我们再来选
学习改进型的时钟置换算法,其实在之前学习的,这个简单的时钟置换算法当中,只是很简单的考虑到了一个页面最近,是否被访问过,但通过之前的讲解我们知道,如果一个被淘汰的,页面没有被修改过的话,那么是不需要执行IO操作,而把它洗回外存的,所以如果说我们,能够,优先淘汰没有被修改过的页面的话,那么实际上就可以,减少这些IO操作的次数,从而让这个置换算法的性能得到,进一步的提升,那这就是改进型的时钟周换算法,的一个思想,所以为了实现这件事,我们还需要为各个页面,增加一个修改位,修改位为0的时候,表示这个页面啊,在内存当中没有被修改过,那修改位为一的时候,表示页面被修改过,那我们在接下来讨论当中,会用访问位,修改位这样的二元组的形式,来标识各个页面的状态,比如说访问位1,修改位也为一的话,那就表示这个页面近期被访问过,并且呃也曾经被修改过,那和简单的时钟置换算法一样,我们也需要把,所有的可能被置换的页面,排成一个循环对列,在第一轮扫描的时候,会从当前位置开始往后依次扫描,尝试找到第一个最近没有被访问过,并且也没有修改过的页面呃,对它进行淘汰,那第一轮扫描,是不修改任何的标志位的,那如果第一轮扫描没有找到零零,这样的页面的话,就需要进行第二轮的扫描,第二轮扫描会尝试找到第一个,最近没有被访问过,但是被修改过的这个页面进行替换,并且被扫描过的那些页面的,访问位都会被设置为0,那如果第二轮扫描失败,需要进行第三轮扫描,第三轮扫描会尝试找到第一个呃,访问位和修改位都为0的这个页面,进行淘汰,并且第三轮扫描,并不会修改任何的标志位,那如果第三轮扫描失败的话,还需要进行第四轮扫描,找到第一个零一的液帧用于替换,那由于第二轮的扫描,已经把所有的访问位,都设为了0了,所以经过第三轮第四轮扫描之后,肯定是可以找到一个呃,要被淘汰的页面的,所以改进行的这种时钟置换算法,选择一个淘汰页面,最多会进行四轮扫描,那其实这个过程,光看文字描述也是很抽象的,不太容易理解,假设系统为一个进程分配了,5个内存块,那当这个内存块被占满之后,各个页面会用这种链接的方式,连成一个循环的对列,那此时如果要淘汰一个页面的话,需要从这个对列的对头开始,依次的扫描,那根据这个算法规则,在第一轮的扫描当中啊,并不修改任何的标志位,需要尝试找到呃,访问位和修改位都为0的,这样一个页面,所以往后寻找了之后,发现这个页面是满足条件的,所以在第一轮扫描的时候,就找到了一个页面用于替换,因此会淘汰这个页面,那这是只需要一轮扫描的情况,再来看下一种情况,那假设此时各个页面的状态是这样的,那如果需要淘汰一个页面的话,那需要从,第一个页面开始往后依次的扫描,然后尝试找到第一个00这样的页帧,并且第一轮的扫描,是不改变任何的标志位的,所以第一轮扫描下来,发现所有的这些啊,都不满足00这样的状态,因此会进行第二轮扫描,第二轮扫描,会尝试找到一个原本就是,01的一个页面,并且扫描过的页面会把访问位置为0,所以在第二轮扫描当中,这个页面被扫描过之后,会把它的这个访问位置为0 那,在扫描到这个页面的时候,发现它原先本来就是零1这样的状态,因此会选择淘汰这个页面,所以,这是需要进行两轮扫描的一个例子,那接着看下种情况,假设此时各个页面的状态是这样的,那和之前一样呃,需要淘汰一个页面的时候,需要进行扫描,一轮到扫描需要找到00这样的页面,但是第一轮扫描下来,发现所有的页面,都没有满足零零这样的条件的,所以会进行第二轮扫描,第二轮扫描会开始寻找,零一这样的页面,并且被扫描过的页面,都会把访问位置为0,因此在经过第二轮的扫描之后,所有的这些页面的访问位,都被置为了0,但是第二轮扫描,依然没有发现原本就是零,一这样的页面,所以就会进行第三轮的扫描,那第三轮扫描需要找到,第一个00这样的页面,那扫描到这个页面的时候,就会发现他已经满足第三轮扫描,啊所要找到这种页面的条件,于是会淘汰这个页面,那这是需要经过三轮扫描的一个例子,那再来看四轮扫描的例子,假设此时所有的,页面的状态都是一1这样的状态,那第一轮扫描的时候,需要找到零零这样的页面,那显然所有的都不满足,第二轮扫描的时候,需要找到01这样的页面,并且被扫描过的页面,访问位都会被置为0,所以经过第二轮扫描之后,所有的这些,页面的访问位都被置为了0,但是依然没有找到原本就是01的页面,于是会进行第三轮的扫描,第三轮扫描会尝试找零零这样的页面,但是也不修改任何的标志位,所以第三轮扫描下来也没发现,满足这个条件的,于是会进行第四轮扫描,第四轮扫描会找到01这样的页面,显然第一个页面此时已经满足条件了,所以此时应该淘汰这个页面,那这,那,这就是需要经过4轮扫描的一个例子,因此通过刚才的这个例子,我们也可以很直观的感受到,改进行的时钟置换算法,在选择一个淘汰页面的时候,最多会进行4轮扫描,而简单的时钟置换算法,在淘汰一个页面的时候,最多只会进行两轮扫描
那我们再从另外一个角度来看,其实第一轮,优先选择淘汰00这样的页面,就意味着,其实第一优先级被淘汰的页面,应该是最近没有被访问过,并且也没有被修改过的页面,那同样的,第二轮要找的是零一这样的页面,所以,第二优先级的应该是最近没有被访问,但是修改过的页面,那如果第二轮,都没有找到一个合适的页面的话,那就说明所有的这些页面在以前,访问位其实都是一,因此其实在第三轮淘汰的这些页面,其实是最近访问过,但是没有修改过的页面,也就是呃访问位以前是一,然后修改位以前是0这样的页面,那同理第四优先级的被淘汰的页面,应该是最近访问过,并且也被修改过的这样的页面,所以,我们也可以用这样的角度来理解啊,各轮选择淘,汰的页面到底是哪种类型的页面,好的那么这个小
节我们介绍了5种页面置换算法,分别是最佳置换先进先出,还有最近最久未使用,还有时钟置换也叫最近未用算法,另外还介绍了改进型的时钟置换,或者叫改进型的最近未用算法,那这个小节的内容,重点需要理解各个算法的算法规则,如果题目中给出一个页面的访问序列,那需要自己,能够用手动的方式来模拟各个算,法运行的一个过程,那除了算法规则之外,各个算法的优缺点,有可能在选择题当中进行考察,那需要重点注意的是,最佳置换算法,在现实当中是无法实现的,然后先进先出算法它的性能差,并且是唯一一个有可能出现,贝拉底异常的算法,好的,那么以上就是这个小节的全部内容
No.15 页面分配策略
各位同学大家好,在这个小节中,我们会学习,页面分配策略相关的一系列知识点,首先我们会学习什么是助流级,之后我们会学习,考试中需要掌握的三种,页面分配置换的策略,另外页面在应该在什么时候被调入,应该从什么地方调入,应该调出到什么位置,这些也是我们之后会探讨的问题,那最后我们又会学习什么是进程抖动,或者叫进程颠簸这种现象,那为了解决进程抖动啊,又引入了工作级这个概念,那我们会按照,从上至下的顺序依次讲解首先
来看一下什么是驻留级,所谓的驻留级其实很简单,就是指请求分页存储管理当中,给进程分配的物理快的集合,或者说内存快页框的集合,它在采用了虚拟存储技术的系统当中,为了从逻辑上提升内存,并且提高内存的利用率,那主流级的大小,一般是要小于进程的总大小的,那接下来我们来考虑一个,比较极端的问题,如果一个进程总共有100个页面,那这个进程的注流极大小,如果是也和这个页面的数量相同,也就是大小为100的话,也就意味着这个进程所有的数据,在刚开始就可以被全部放入内存,并且运行期间,就不会再发生任何一次缺液,如果驻留级太小的话,啊比如说驻留级大小为一,那这个进程他可能会使用到100个页面,所以如果说,这个进程只有一个物理块可以使用,那么这个进程在运行的期间,肯定会产生大量的频繁的缺液,所以从这个极端的例子当中,我们可以看到,如果说驻留级选择的太小的话,就会导致这个进程缺液频繁,系统就需要花很大的时间来处理缺液,而实际用于进程推进,进程运行的时间又很少,但如果驻留级太大的话,又会导致多道品程序的并发度下降,使系统的某些资源利用率不高,那为什么资源利用率会降低呢,可以这么考虑,比如说像系统当中的CPU,还有IO设备这两种资,源理论上是可以并行的工作的,那如果说多道程序并发度下降,就意味着啊,CPU和IO设备这两种资源并行工作的,这种几率就会小很多,所以资源的利用率当然就会有所降低,所以系统应该为,进程选择一个合适的助流级大小,那针对于助流级的大小是否可变,这个问题,人们提出了固定分配和可变分配,这两种分配策略,固定分配就是,系统在刚开始的时候,就给进程分配一组固定数目的物理块,并且在运行期间不再改变,也就是助流级的大小,只刚开始就确定了,之后就不再改变了,可变分配啊,就是刚开始会给,进程分配一定数目的物理快,但是在运行期间,可以根据情况适当的增加或者减少,所以可变分配,其实指的就是,注流机的大小是可以动态的改变,可以调整的,另外当页面置换的时候,置换的范围应该是什么,根据这个问题,人们又提出了局部置换和全局置,换这两种置换范围的策略,局部置换就是指当发生缺液的时候,只能选择进程自己的物理块进行置换,如果采用的是全局置换的话,当发生缺液的时候,操作系统会把,自己保留的空闲物理块,分配给这个缺液的进程,当然也可以将别的进程,所持有的物理块给置换到外存去,然后再把这个物理块分配给现在,缺液的这个进程,所以,局部置换和全局置换的区别就在于,当某个进程发生缺页,并且需要置换出某个页面的时候,那这个,置换出的页面是不是只能是自己的,那,把这两种分配和置换的策略两两结合,可以达到这样的,三种分配和置换的策略,分别是固定分配局部置换,可变分配局部置换,和可变分配全局置换,但是大家会发现,其实并不存在,固定分配全局置换这种策略,因为从全局置换的这个规则,我们也可以知道,如果使用的是全局置换的话,就意味着一个进程所拥有的物理快,是必然会改变的,而固定分配又规定着,进程的驻留级大小不变,也就是这,进程所拥有的物理快数是不能改变的,所以固定分配全局置换这种,分配置换策略是不存在的,那接下来我们依次介绍存在的这三种,分配和置换的策略
固定分配局部置换是指,系统会为各个进程,分配一定数量的物理快,并且在整个运行期间啊,这些物理快速都不再改变,那如果说进程在运行的过程中,发生了缺页的话,那么就只能从这个进程,在内存当中的某个页面当中,选出一页进行换出,然后再调入所需要的页面,所以这种策略也有一个很明显的缺点,就是很难在刚开始的时候,就确定,应该为每个进程分配多少个物理块,才能才算合适啊,不过在实际应用中啊,一般如果说采用这种策略的系统,它会根据进程大小,进程优先级,或者是程序员提出的一些参数,来确定,到底要给每个进程分配多少个物理块,不过这个数量一般来说是不太合理的,那因为助流机的大小不可变,所以固定分配,局部制化,这种策略的灵活性,相对来说是比较低的,那第二种叫做可变分配全局制化,因为是可变分配,所以说系统刚开始会为,进程分配一定数量的物理块,但是之后在进程运行期间,呃这个物理块的数量是可以改变的,那操作系统,会保持一个空闲物理块的对列,如果说一个进程发生缺液的时候,就会从这个空闲物理块当中取出一个,啊分配给进程,如果说此时这个空闲物理块,都已经用完了,那就可以选择一个系统当中,未锁定的页面,换出外存,再把呃这个物理块分配给,缺页的这个进程,那这个地方所谓的未锁定的页面,指的是什么呢,其实系统会锁定一些很重要的,就是不允许被换出外存,需要长度内存的页面,比如说,系统当中的某些很重要的内核数据,就有可能是被锁定的,那另外一些可以被置换出外存的页面,就是所谓的未锁定的页面,当然这个地方只是做一个拓展,在考试当中应该不会考察,那通过刚才对这个策略的描述,大家也会发现,在这种策略当中,只要进程发生缺液的话,那他必定会获得一个新的物理化,如果说空闲物理块没有用完,那这个新的物理块,就是从空闲物理块对列当中,选择一个给他分配,那如果说空闲物理块用完了,系统才会,选择一个未锁定的页面换出外存,但这个未锁定的页面有可能是任,何一个进程的页面,所以这个进程的页面被换出的话,那么他所拥有的物理块就会减少,他的缺页率就会有所增加,那显然只要进程发生了缺液,就给他分配一个新的物理块,这种方式其实也是不太合理的,所以之后,人们又提出了可变分配,局部置换的策略,在刚开始,会给进程分配一定数量的物理块,呃因为是可变分配,所以之后这个物理块的数量也是会,改变的那由于是局部置换,所以当进程发生缺液的时候,只允许这个进程从自己的物理块当中,选出一个进行换出,如果说操作系统在进程运行的过程中,发现他频繁的缺液,那就会给这个进程多分配几个物理块,直到这个进程的缺液率,回到一个适当的程度,那相反的,如果一个进程在运行当中,缺液率特别低的话,那么系统会适当的减少,给这个进程所分配的物理块,那这样的话,就可以让系统的多道程序并发度,呃也保持在一个相对理想的位置,那这3种策略当中,最难分辨的是,可变分配全局置换和可变分配,局部置换,大家需要抓住他们俩啊,最大的一个区别,如果采用的是全局置换策略的话,那么只要缺液,就会给这个进程分配新的物理块,那如果说,采用的是这种局部置换的策略的话,系统会根据缺液的频率,来动态的,增加或者减少一个进程所用的物理块,这是三种,我们需要掌握的页面分配策略,有可能在选择题当中进行考察
接下来,我们再来讨论下一个问题,我们应该在什么时候,掉入所需要的页面呢,那一般来说有这样的两种策略,第一种叫做啊预掉页策略,根据我们之前学习的局部性原理,特别是空间局部性的原理,我们知道,如果说当,前访问了某一个内存单元的话,那么很有可能在之后不久的将来,会接着访问,与这个内存单元相邻的那些内存单元,所以根据这个思想,我们自然而然的也会想到,如果说我们访问了某一页面的话,那么是不是在不久的之后,就有可能,会访问与他相邻的那些页面呢,因此基于这个方面的考虑,如果我们能够一次掉入若干个,相邻的页面,那么可能会比一次,掉入一个页面会更加高效,因为我们一次掉入一堆页面的话,那么我们启动磁盘IO的次数肯定就会,少很多,这样的话就可以提升掉页的效率,不过另一个方面,如果说我们提前掉入的这些页面啊,在之后没有被访问过的话,那么,这个预掉页又是一种很低效的行为,所以我们可以用某种方法,预测不久之后可能会访问到的页面,将这些页面预先的掉入内存,但目前预测的成功率不高只有50%左右,所以在实际应用当中,预掉页策略,主要是用于进程首次掉入的时候,由程序员指出,哪些部分应该是先掉入内存的,比如说我可以告诉系统,把麦函数相关的那些部分先调入内存,所以预调页策略是在,进程运行前就进行调入的一种策略,那第二种就是请求调页策略,这也是咱们之前一直在学习的,请求调页方式,只有在进程运行期间发现缺页的时候,才会把所缺的页面调入内存,所以这种策略其实在,进程运行期间才进行页面的调入,并且被调入的页面,肯定在之后是会被访问到的,但是由于每次只能调入一个页面,所以每次调页都需要启动磁盘IO操作,因此IO开销是比较大的,在实际用当中,预钓页策略和请求钓页,策略都会结合着来使用,预钓页用于进程运行前的调入,而请求钓页策略是在进程运行期间,使用的那这是钓入页面的实际问题,那接下来
我们再来看一下,我们应该从什么地方掉入页面,之前我们有简单介绍过,此盘当中的存储区,分为兑换区和文件区这样两两个部分,其中兑换区采用的是连续分配的方式,读写的速度更快,而文件区的读写速度是更慢的,它采用的是离散分配的方式,那什么是离散分配什么是连续分配,这个是咱们在,之后的章节会学习的内容,这个地方先啊不用管有个印象就可以,在本章中大家只需要知道啊,兑换区的读写速度更快,而文件区的读写速度更慢就可以了,那一般来说,文件区的大小要比兑换区要更大,那平时我们的程序在没有运行的时候,相关的数据都是存放在文件区的,那由于兑换区的读写速度更快,所以如果说,系统拥有足够的兑换区空间的话,那么页面的调入调出都是,内存与兑换区之间进行的,所以系统中如果有足够的兑换区空间,那刚开始在运行之前,会把,我们的进程相关的那一系列数据,从文件区,先复制到兑换区,之后把这些,需要的页面从兑换区调入内存,相应的如果内存空间不够的话,可以把内存中的某些页面啊调出到,兑换区当中,页面的调入调出,都是内存和兑换区这个更高速的,区域进行的,那这是在兑换区大小足够的情况下,使用的一种方案
那如果说,系统中缺少足够的兑换区空间的话,凡是不会被修改的数据,都会从文件区直接掉入内存,那由于这些数据是不会被修改的,所以当调出这些数据的时候,并不需要重新写回磁盘,那如果说某些页面被修改过的话,把它调出的时候就需要写回到兑换区,而不是写回到文件区,因为文件区的不行,如果之后还需要再,使用到这些被修改的页面的话,那就是从兑换区再换入内存,第三种
Unix使用的是这样的一种方式,如果说一个页面还没有被使用过,也就是这个页面第一次被使用的话,那么它是从文件区直接掉入内存,但之后如果内存空间不够,需要把某些页面换出外存的话,那么是换出到这个兑换区当中,那如果这个页面需要再次被使用的话,呃就是要从兑换区再换回内存,这是Unix系统采用的一种方式,那接下来我们
我们再来介绍一个,呃很常考的一个概念,叫做抖动或者叫颠簸现象,所谓的抖动或者颠簸就是指,刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,所以这种频繁的页面调度行为,就是所谓的抖动或者叫颠簸,产生这个现象的主要原因啊,是在于进程频繁访问的页面数目,要高于可用的物理快数,也就是说,分配给进程的物理快是不够的,那如果说发生了抖动现象的话,系统会用大量的时间来处理,啊这个进程页面的患入患出,而实际用于进程执行的时间,就变得很少,所以我们要尽量避免抖动现象的发生,那为了防止抖动的发生,就需要为进程分配足够的物理块,但如果说物理块分配的太多的话,又会降低系统整体的并发度,降低某些资源的利用率,所以为了研究应该为每个进,应该为每个进程分配多少个物理块啊,有一个科学家在一九六几年,提出了进程工作级的概念,所谓的工作
集就是指进程在某段时间间隔内,实际访问的页面的集合,注意它和驻流集其实是呃有区别的,驻流集是指在请求分页存储管理当中,给进程分配的内存快的集合,我们直接来看个例子,一般说操作系,统会设置一个所谓的窗口尺寸,来算出工作级,那假设一个进程对页面的访问序列是,啊这样的一个序列,那如果此时访问到了这个页面,并且窗口尺寸为4的话,那么就会从此时访问的这个页面开始,往前寻找之前访问过的4个页号,由此来确定工作级的内容,所以在这个时刻啊,这个进程的工作级应该是24151823,那此时如果访问到的是这个页面,那同样的再往前看四个页号,就会发现,此时的工作级是18247这样三个页面,所以从这个地方会发现,工作级的大小,呃可能会小于窗口的尺寸,在实际应用当中,窗口尺寸一般会设置的更大一些,比如说设置1510100这样的数字,那对于一些局部性很好的进程来说,呃工作级的大小,一般是要比窗口尺寸的大小要更小的,比如说窗口尺寸为5,但是经过一段时间的监测,发现某个进程的工作季最大只会为3,那么就说明,这个进程是拥有很好的居务性的,那系统可以给这个进程分配,三个或者3个以上的内存款,就可以满足这个进程的运行需要了,所以系统可以根据监测工作级的大小,来决定,到底要给这个进程分配多少个内存款,换一个说法,就是根据工作级的大小,来确定主流级的大小到底是多少,那一般来说,助流级的大小不能小于工作级的大小,如果说更小的话,那就有可能会发生频繁的缺液,也就是发生抖动现象,另外在有的系统当中,也会根据工作级的概念,来设计一种页面置换算法,比如说如果说这个进程,需要置换出某个页面的话,那完全就可以选择一个,不在工作级当中的页面,进行淘汰,那这些知识点只是作为一个拓展,大家只要有个印象就可以了,好的那么这个小节,我们介绍了页面分配策略相关的
系列知识点,需要特别注意助流级这个概念,在之前咱们讲过的那些内容当中啊,经常会遇到某些题目,告诉我们一个条件,就是说啊,系统为某个进程分配了n个物理块,那这种说法,其实也可以改变一种等价的表述方式,就是也可以说成是,某个进程的助流级大小是n,那如果说题目中的,条件,是用助流及大小这种方式给出的话,大家也需要知道,他所表述的到底是什么意思,那另外大家需要注意,这3种分配置换策略,在真题当中是进行考察过的,并且在有的大题当中,有可能会告诉大家,一个进程采用固定分配,局部置换的策略,那这个条件就是为了告诉大家,系统为一个进程分配的物理快速,是不会改变的,大家在做客户习题的时候,可以注意一下,很多大题都会给出这样的一个条件,那我们需要知道,这个条件背后隐含的一系列的信息,那这个地方还需要注意,并不存在固定分配全局置换这种策略,因为全局置换意味着,一个进程所拥有的物理快速,肯定是会改变的,而固定分配,又要求一个进程拥有的物理快速,是不能改变的,所以固定分配和全局置换,这两个条件本身就是相互矛盾的,因此并不存在固定分配,全局置换这种方式,那之后介绍的内容何时掉入页面,应该从何处掉入页面,这些呃能有个印象就可以了,最后大家还需要重点关注抖动,颠簸这个现象,那产生抖动的主要原因是,分配给进程的物理块不够,所以如果要解决抖动问题的话,那么肯定就是用某种方法,给这个进程分配更多的物理块,那这一点,在咱们的课后习题当中也会遇到,那我们还对工作级的概念,做了一系列的拓展,不过一般来说,工作级这个概念不太容易进行考察,但是大家需要注意的是,助流级的大小,一般来说不能小于工作级的大小,如果更小的话那就会产生抖动现象,那这个小节的内容,一般来说只会在选择题当中进行考察,但是在考试当中也有可能用某些概念,作为大题当中的一个条件进行给出,所以大家还需要通过课后习题,进行进一步的,巩固好的,那么以上就是这个小节的全部内容
No.16 内存映射文件
各位同学大家好,在这个视频中,我们要学习内存映射文件,首先,我们会聊一聊内存映射文件是什么,以及有什么作用,接下来为了理解内存映射文件的特点,我们会简要的介绍,传统的文件访问方式,以此作为对比,最后我们会学习内存映,射文件的实现原理和作用,首先来看看什么,
什么是内存印式文件,简单来说,这是操作系统向上层的程序员,提供的一个系统标准功能,通过这个功能,程序员可以很方便的去访问文件数据,另外,这个功能也可以很方便的让多个进程,共享同一个文件的数据,先来解释第一点,为什么说内存映射文件,可以让程序员更方便的去使用,文件数据呢,那作为对比,我们先来看一下传统的文件访问方式,啊来看个例子,这是一个文件名字叫葵花宝典点TST,这个文件要存放到磁盘里边,那磁盘的存储空间是以块为单位的,这样的一块大小是1KB,那相应的,这个文件,就会被拆分成几个大小相等的块,每个块刚好是1KB,刚好可以放到这个磁盘里边,那这些块,有可能被,离散的存放到磁盘的各个角落,就像这个样子,那如果一个进程,想要访问这个文件的数据,应该怎么做呢,传统的做法是这样的,首先我们知道,每个进程他拥有自己的虚拟地址空间,那如果这个进程,想要访问这个文件的数据,首先他需要使用open系统调用,来指明打开这个文件,接下来需要使用six系统调用啊,来指明他想要读取这个文件的,哪部分数据,那操作系统会用一个读写指针来记录,这个位置,接下来,进程可以使用red系统调用来指明,从这个位置往,后他想要读入多少的数据,比如读入10个字节,或者读入20个字节等等,那如果这次进程要读入的这部分数据,刚好是存放在文件的第二个快件,那么接下来,操作系统就会把这一块的数据,给读入内存,好现在这部分的数据被读入内存了,那进程是不是就可以去访,问内存里的这部分数据了,当然进程也可以修改这一块的数据,好最后如果想让刚才的修改被保存,那么这个进程,他还需要使用right系统标用,把内存里的这一块数据写回词盘,写回词盘,所以这种传统的文件访问方式,听起来很麻烦,对吧,那能不能让读写文件数据的这些操作,变得更简单呢,这就是内存映射文件要解决的问题
,好来看一下,如果一个操作系统,它支持内存映射文件的功能,那么一个程序员或者说一个进程,它访问文件的方式就会变得更简单,首先需要先使用open系统标用,指明打开一个文件,接下来使用MF这个系统标用,让操作系统,把,文件映射到进程的虚拟地址空间当中,也就是这样子,那这个系统调用,会给程序员返回一个指针,这个指针会指向,刚才映射的这片区域的起始地址,那接下来,你就可以用访问内存的方式去访问,呃这些文件数据了,什么意思呢,我们都写过c语言程序,如果给你一个呃即使地址某一个指针,那么你是不是可以用这个指针再加上,某一个地址的偏移量,去访问这个指针后面的某些区域对吧,所以只要MF这个系统调用,给程序员返回了这片区域的起始地址,那接下来用这个指针就可以访问到,这个文件的任何一个数据,那你会发现在这个图里边,我们把文件的3个块涂成了灰色,原因是在使用Max系统标准之后,操作系统只是建立了文件数据,和内存之间的一个映射关系,但并没有把文件数据直接给读入内存,这就相当于一个缺页的状态,好所以接下来的故事是这样的,假定此时你要访问的呃数据,刚好是在文件的第二块,在这个部分,那此时操作系统发现,这一块的数据还没有掉入储存,对吧也就是出现了一个缺页异常,那此时,操作系统会自动的把这一块的数据,给读入储存,那同样的道理,如果你此时想要访问第3块数据,而第3块数据,此时还处于缺页状态的话,那操作,系统会自动的帮你把第3块数据,导到内存里,也就是说我们作为程序员,我们不需要再自己去调用read函数,读入数据的过程,是由操作系统自动的帮我们完成的,好那这些数据被读入内存之后,是不是进程就可以对他们为所欲为,比如说我可以修改第二块的数据,好最后,如果说,这个进程他不再需要使用这个文件,那么进程可以使用close,系统调用来关闭文件,当他关闭文件之后,操作系统会自动的把文件当中,被修改的数据,给写回磁,盘,那第二块数据是被修改过的而第三,而第三块数据是没有维修改过的,所以,操作系统会把第二块数据写回字旁,好,因此可以看到采用内存映射文件之后,程序员,对这个文件数据的访问就方便多了,他只需要知道,这个文件在内存当中的起始地址,接下来按照访问内存的方式,去访问这个文件当中的数据就可以,那文件数据的读入或者写出,都是由操作系统自动来完成的,相比之下,传统的文件访问方式,需要程序员自己去调用read和write,系统调用,才可以读入,文件的数据或者写出文件数据,对吧好,那现在你已经知道了,为什么内存映射文件,可以让程序员更方便的,去使用文件数据了,那接下来,我们再来解释,内存映射文件的第二个作用,可以实现文件数据的共享,那通过之前的学习我们知道,葵花宝典点TXT这个文件,它可以被进程一用系统调用的方式,映射到自己的虚拟地址空间里,那同样的道理,另一个进程,进程2是不是也可以,把这个文件,映射到自己的虚拟地址空间里边,那此时两个进程的虚拟地质空间,是相互独立的,但是操作系统会把,这两块虚拟地质空间,映射到相同的物理内存上,这应该不难理解吧,操作系统是不是只需要,修改这两个进程的页表,让对应的页面,映射到相同的一个物理页框上,那这么做是不是就可以让两个进程,实际上是在共享同一份文件的数据,那在这种情况下,当一个进程修改了文件的数据之后,另一个进程是不是立马也可以看到,这一块文件数据的改变,好所以通过内存映射文件的方式,多个进程他们可以共享,同一个文件的数据,好的那大家可以再根据这页PPT,来回顾一下内存映射文件,相关的知识,那最后补充一点文件数据的
读入和写出,完全是由操作系统来负责的,就是,什么时候要读入一个文件的数据快,什么时候要写出一个文件的数据快,这都是由操作系统来控制的,所以这么做的好处在于,操作系统它可以通过某些策略,去优化磁盘IO的效率,比如说用预读入或者缓写出,这样的策略可以优化IO的效率,那这就不再展开讨论,大家有个大致的了解就可以了,好的那以上就是这个小节的全部内容,