diff --git a/Operate-System/1-process-management.md b/Operate-System/1-process-management.md index 4dd7ee8..2c96b87 100644 --- a/Operate-System/1-process-management.md +++ b/Operate-System/1-process-management.md @@ -360,7 +360,7 @@ + 缺点:排在长作业(进程)后面的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好。即FCFS算法对长作业有利,对短作业不利。 + 是否会导致饥饿:不会。 -**例题:**各进程到达就绪队列的时间、需要的运行时间如下表所示。使用先来先服务调度算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间。 +**例题** 各进程到达就绪队列的时间、需要的运行时间如下表所示。使用先来先服务调度算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间。 进程|到达时间|运行时间 :--:|:-----:|:------: @@ -406,7 +406,7 @@ P4|5|4|7|12|16 3.虽然严格来说,SJF的平均等待时间、平均周转时间并不一定最少,但相比于其他算法(如FCFS),SJF依然可以获得较少的平均等待时间、平均周转时间。 4.如果选择题中遇到“SJF算法的平均等待时间、平均周转时间最少”的选项,那最好判断其他选项是不是有很明显的错误,如果没有更合适的选项,那也应该选择该选项。 -**例题:**各进程到达就绪队列的时间、需要的运行时间如下表所示。使用非抢占式短进程优先调度算法和抢占式短进程优先调度算法,分别计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间。 +**例题** 各进程到达就绪队列的时间、需要的运行时间如下表所示。使用非抢占式短进程优先调度算法和抢占式短进程优先调度算法,分别计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间。 进程|到达时间|运行时间 :--:|:-----:|:------: @@ -440,7 +440,7 @@ P4|5|4 + 对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长作业饥饿的问题。 + 是否会导致饥饿:不会。 -**例题:**各进程到达就绪队列的时间、需要的运行时间如下表所示。使用高响应比优先调度算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间。 +**例题** 各进程到达就绪队列的时间、需要的运行时间如下表所示。使用高响应比优先调度算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间。 进程|到达时间|运行时间 :--:|:-----:|:------: @@ -473,7 +473,7 @@ P4|5|4 + 如果时间片太小,进程切换会频繁发生,需要保存现场恢复环境,增加时间开销。 + 一般设计时间片段时要让切换进程的开销不超过1%。 -**例题:**各进程到达就绪队列的时间、需要的运行时间如下表所示。使用时间片轮转调度算法,分析时间片大小为2时的进程运行状态。 +**例题** 各进程到达就绪队列的时间、需要的运行时间如下表所示。使用时间片轮转调度算法,分析时间片大小为2时的进程运行状态。 进程|到达时间|运行时间 :--:|:-----:|:------: @@ -538,7 +538,7 @@ P4|5|4 + 若进程占用处理机很长时间,则降低其优先级。 + 若进程频繁进行I/O操作,则提升其优先级。 -**例题:**各进程到达就绪队列的时间、需要的运行时间、进程优先数如下表所示。使用非抢占式与抢占式优先级调度算法,分析进程运行状态。(优先级越大,优先级越高) +**例题** 各进程到达就绪队列的时间、需要的运行时间、进程优先数如下表所示。使用非抢占式与抢占式优先级调度算法,分析进程运行状态。(优先级越大,优先级越高) 进程|到达时间|运行时间|优先数 :--:|:-----:|:------:|:---: @@ -596,7 +596,7 @@ P4|5|4|2 + 可灵活地调整对各类进程的偏好程度,比如CPU密集型进程、I/O密集型进程(拓展:可以将因I/O而阻塞的进程重新放回原队列,这样I/O型进程就可以保持较高优先级) + 是否会导致饥饿:会。 -**例题:**各进程到达就绪队列的时间、需要的运行时间如下表所示。使用多级反馈队列调度算法,分析进程运行状态。 +**例题** 各进程到达就绪队列的时间、需要的运行时间如下表所示。使用多级反馈队列调度算法,分析进程运行状态。 进程|到达时间|运行时间 :--:|:-----:|:------: @@ -1583,7 +1583,7 @@ Pi() { 可以在资源分配之前预先判断这次分配是否会导致系统进入不安全状态,以此决定是否答应资源分配请求。这也是“银行家算法”的核心思想。 -**例题:**系统中有5个进程P0到P4,3种资源ROR到2,初始数量为(10,5,7),某一时刻的情况可表示如下: +**例题** 系统中有5个进程P0到P4,3种资源ROR到2,初始数量为(10,5,7),某一时刻的情况可表示如下: 进程|最大需求|已分配 :-:|:------:|:----: diff --git a/Operate-System/2-memory-management.md b/Operate-System/2-memory-management.md index aa34cec..93c0b13 100644 --- a/Operate-System/2-memory-management.md +++ b/Operate-System/2-memory-management.md @@ -53,53 +53,59 @@ + 单一连续分配。 + 固定分区分配。 + 动态分区分配。 -+ 非连续分配管理 ++ 非连续分配管理(离散分配方式): + + 基本分页存储管理。 + + 基本分段存储管理。 + + 段页式存储管理。 连续分配是指为用户进程分配的必须是一个连续的内存空间。而非连续分配反之。 + 内部碎片,分配给某进程的内存区域中,如果有些部分没有用上。 + 外部碎片,是指内存中的某些空闲分区由于太小而难以利用。 -#### 连续分配管理 +#### 在单一连续分配 -1. 在单一连续分配: - + 内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据:用户区用于存放用户进程相关数据。 - + 内存中只能有一道用户程序,用户程序独占整个用户区空间。 - + 优点: - + 实现简单。 - + 无外部碎片。 - + 可以采用覆盖技术扩充内存。 - + 不一定需要采取内存保护(如早期的PC操作系统Ms-Dos)。 - + 缺点: - + 只能用于单用户、单任务的操作系统中。 - + 有内部碎片。即分配给某进程的内存区域中,如果有些区域没有用上的部分 - + 存储器利用率极低。 -2. 固定分区分配: - + 将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。 - + 分区的方式: - + 分区大小相等:缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合。 - + 分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分(比如:划分多个小分区、适量中等分区、少量大分区)。 - + 记录分区的方法:操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的天小、起始地址、状态(是否已分配)。 - + 分区分配过程:当某用户程序要装入内存时,由操作系统内核程序根据用户程序大小检索该表,从中找到一个能满足大小的、未分配的分区,将之分配给该程序,然后修改状态为“己分配”。 - + 优点: - + 实现简单。 - + 无外部碎片。 - + 缺点: - + 当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但这又会降低性能。 - + 会产生内部碎片,内存利用率低。 -3. 动态分区分配: - + 动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。 - + 记录分区的方法: - + 空闲分区表:每空闲分区对应表项。表项中包含分区号、分区大小、分区起始地址、分区状态等信息。 - + 空闲分区链:每个分区的起始部分和末尾部分分别设置前向指针和后向指针。起始部分处还可记录分区大小等信息。 - + 分配分区: - + 当选择的分区分区大小大于分配空间,则分区大小相减,并修改起始地址。 - + 当选择的分区分区大小等于分配空间,则删除该表项。 - + 回收分区: - + 若回收区的后面或前面有一个相邻的空闲分区则合并为一个。 - + 若回收区的后面和前面都有一个相邻的空闲分区则合并为一个。 - + 若回收区的后面或前面都没有一个相邻的空闲分区,则增加一个表项。 - + 动态分区分配会导致外部碎片,可用通过**紧凑**(拼凑)技术来移动进程位置合并空闲空间。 ++ 内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据:用户区用于存放用户进程相关数据。 ++ 内存中只能有一道用户程序,用户程序独占整个用户区空间。 ++ 优点: + + 实现简单。 + + 无外部碎片。 + + 可以采用覆盖技术扩充内存。 + + 不一定需要采取内存保护(如早期的PC操作系统Ms-Dos)。 ++ 缺点: + + 只能用于单用户、单任务的操作系统中。 + + 有内部碎片。即分配给某进程的内存区域中,如果有些区域没有用上的部分 + + 存储器利用率极低。 + +#### 固定分区分配 + ++ 将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。 ++ 分区的方式: + + 分区大小相等:缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合。 + + 分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分(比如:划分多个小分区、适量中等分区、少量大分区)。 ++ 记录分区的方法:操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的天小、起始地址、状态(是否已分配)。 ++ 分区分配过程:当某用户程序要装入内存时,由操作系统内核程序根据用户程序大小检索该表,从中找到一个能满足大小的、未分配的分区,将之分配给该程序,然后修改状态为“己分配”。 ++ 优点: + + 实现简单。 + + 无外部碎片。 ++ 缺点: + + 当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但这又会降低性能。 + + 会产生内部碎片,内存利用率低。 + +#### 动态分区分配 + ++ 动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。 ++ 记录分区的方法: + + 空闲分区表:每空闲分区对应表项。表项中包含分区号、分区大小、分区起始地址、分区状态等信息。 + + 空闲分区链:每个分区的起始部分和末尾部分分别设置前向指针和后向指针。起始部分处还可记录分区大小等信息。 ++ 分配分区: + + 当选择的分区分区大小大于分配空间,则分区大小相减,并修改起始地址。 + + 当选择的分区分区大小等于分配空间,则删除该表项。 ++ 回收分区: + + 若回收区的后面或前面有一个相邻的空闲分区则合并为一个。 + + 若回收区的后面和前面都有一个相邻的空闲分区则合并为一个。 + + 若回收区的后面或前面都没有一个相邻的空闲分区,则增加一个表项。 ++ 动态分区分配会导致外部碎片,可用通过**紧凑**(拼凑)技术来移动进程位置合并空闲空间。 动态分区分配算法,为了解决动态分区分配方式中如何从多个空闲分区中选择一个分区分配: @@ -131,24 +137,96 @@ 所以综合来看,首次适应算法效果最好就。 -#### 非连续分配管理 +#### 基本分页存储管理 -也称为离散分配方式。分为三种: ++ 将内存空间分为一个个大小相等的分区(比如每个分区4KB),每个分区就是一个“页框”,或称“页帧”、“内存块”、“物理块”。每个页框有一个编号,即“页框号”(或者“内存块号”、“页帧号”、“物理块号”)页框号从0开始。 ++ 将用户进程的地址空间也分为与页框大小相等的一个个区域,称为“页”或“页面”。每个页面也有一个编号,即“页号”,页号也是从0开始。所以页面不同于页框,是进程的逻辑概念。(进程的最后一个页面可能没有一个页框那么大。因此,页框不能太大,否则可能产生过大的内部碎片) ++ 操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。 ++ 各个页面不必连续存放,也不必按先后顺序来,可以放到不相邻的各个页框中。 ++ 为了方便计算页号、页内偏移量、页面大小一般设为出的整数幂。 ++ 如果每个页面大小为$2^k$B,用二进制数表示逻辑地址,则末尾k位即为页内偏移量,其余部外就是页号 ++ 因为允许将进程的各个页离散地存储在内存不同的物理块中,但系统应能保证进程的正确运行,即能在内存中找到每个页面所对应的物理块,所以为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表,其中页表大小也与页面一样被页框约束。 + + 一个进程对应一张页表。 + + 进程的每一页对应一个页表项。 + + 每个页表项由“页号”和“块号”组成。完成从逻辑的页号向物理的块号的映射。 + + 页表记录进程页面和实际存放的内存块之间的对应关系。 -+ 基本分页存储管理: - + 将内存空间分为一个个大小相等的分区(比如:每个分区4KB),每个分区就是一个“页框”,或称“页帧”、“内存块”、“物理块”。每个页框有一个编号,即“页框号”(或者“内存块号”、“页帧号”、“物理块号”)页框号从0开始。 - + 将用户进程的地址空间也分为与页框大小相等的一个个区域,称为“页”或“页面”。每个页面也有一个编号,即“页号”,页号也是从0开始。(注:进程的最后一个页面可能没有一个页框那么大。因此,页框不能太大,否则可能产生过大的内部碎片) - + 操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。 - + 各个页面不必连续存放,也不必按先后顺序来,可以放到不相邻的各个页框中。 - + 逻辑地址转换为物理地址: - 1. 要算出逻辑地址对应的页号。页号=逻辑地址/页面长度(取除法的整数部分) - 2. 要知道该页号对应页面在内存中的起始地址。页面在内存中的起始位置是操作系统需要用某种数据结构记录进程各个页面的起始位置。 - 3. 要算出逻辑地址在页面内的“偏移量”。 - 4. 物理地址=页面始址+页内偏移量。页内偏移量=逻辑地址%页面长度(取除法的余数部分) - + 为了方便计算页号、页内偏移量、页面大小一般设为出的整数幂。 - + 如果每个页面大小为$2^k$B,用二进制数表示逻辑地址,则末尾k位即为页内偏移量,其余部外就是页号 -+ 基本分段存储管理 -+ 段页式存储管理。 +**例题** 假设某系统物理内存大小为4GB,页面大小为4KB,则每个页表项至少应该为多少字节? + +4GB = $2^{32}$B,4KB = $2^{12}$B。 + +因此4GB的内存总共会被分为$2^{32}/2^{12}= 2^{20}$个内存块,因此内存块号的范围应该是$0\cdots2^{20}-1$,因此至少要20个二进制位才能表示这么多的内存块号,因此至少要3个字节才够,因为每个字节8位,$3\times8=24$。 + +所以最少为三个字节。 + +深入来看,因为每页表项会顺序连续存储在内存中,若该页表在内存中存放的起始地址是X,则M号页对应的页表项存放在内存地址X+3*M。 + +同时因为页面大小为4KB,所以每个页框(即可用存放的最大值)大小为4*1024/3=1365个页表项,但是此时会余下4\*1024/3=1B页内碎片,所以一定会在中间空出1B内存,所以1365号页在页框约束下会在新的下一个页框存储,表项会存放在X+3\*1365+1处。这时候地址公式就不管用了。 + +而如果每个页表项占4字节,则每个页框刚好能放下1024个页表项,从而没有余数,能减少查找的麻烦。 + +所以理论上3B就能表示内存块的范围,但是为了方便页表查找(对齐),实际上会多一些字节,使得每个页面能装下整数个页表项。 + +#### 基本地址变换机构 + +可用借助页表进行转换,通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F和页表长度M(即这个进程里有多少页)。进程未执行时,页表的始址和页表长度放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把它们放到页表寄存器中。 + +在页式存储管理的系统中时,只用确定页面大小和逻辑结构就能得到物理地址。 + +基本地址变换机构需要先查询页表,再查询内存两次操作: + +1. 要算出逻辑地址A对应的页号P与页内偏移量W。页号P=逻辑地址A/页面长度L(取除法的整数部分)。页内偏移量W=A逻辑地址%页面长度L(取除法的余数部分)。 +2. 检测页号P是否越界。如果页号P大于等于页表长度M,则内中断(因为页号从0开始,页表长度至少为1,从而P=M页会越界)。 +3. 根据页表寄存器中的页表项地址PA=页表起始地址F+页号P*页表项长度PL,得到页表中对应的页表项,从而确定页面存放的内存块号B。 + + 页表长度指的是这个页表中总共有几个页表项,即总共有几个页。 + + 页表项长度指的是每个页表顶占多大的存储空间。 + + 页面大小指的是一个页面占多大的存储空间。 +4. 最后物理地址E=内存块号B*页面大小L+页内偏移量W(如果内存块号和业内偏移量用二进制表示,则直接拼接起来就是最终物理地址了)。 + +**例题** 若页面大小L为1K字节,页号2对应的内存块号B=8,将逻辑地址A=2500转换为物理地址E。 + +等价描述:某系统按字节寻址,逻辑地址结构中,页内偏移量占10位,页号2对应的内存块号b=8,将逻辑地址A=2500转换为物理地址E。 + +按照等价描述,若一个页面的页内偏移量占10位,所以页面大小需要10位来表示,即页面大小为$2^{10}B=1KB$。 + +第一步,计算页号和页内偏移量。页号P=A/L=2500/1024=2,页内偏移量W=A%L=2500%1024=452。 + +第二步,没有越界,其存放的内存块号为8。 + +第三步,物理地址E=B\*L+W=8\*1024+452=8848。 + +#### 具有快表的地址变换机构 + ++ 时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问(因为程序中存在大量的循环)。 ++ 空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问(因为很多数据在内存中都是连续存放的)。 ++ 快表,又称相连寄存器(TLB),是一种访问速度比内存快很多的高速缓冲存储器,用来存放当前访问的若干页表项,以加速地址变换的过程。与此对应,内存中的页表常称为慢表。 ++ 由于查询快表的速度比查询页表的速度快很多,因此只要快表命中,就可以节省很多时间。 ++ 因为局部性原理,一般来说快表的命中率可以达到90%以上。 ++ 快表的地址变换过程: + 1. CPU给出逻辑地址,由某个硬件算得页号、页内偏移量,将页号与快表中的所有页号进行比较。 + 2. 如果找到匹配的页号(即命中),说明要访问的页表项在快表中有副本,则直接从中取出该页对应的内存块号,再将内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表命中,则访问某个逻辑地址仅需一次访存即可。 + 3. 如果没有找到匹配的页号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。同时将其存入快表,以便后面可能的再次访问。但若快表已满,则必须按照一定的页面置换算法对旧的页表项进行替换。因此,若快表未命中,则访问某个逻辑地址需要两次访存。 + +**例题** 某系统使用基本分页存储管理,并采用了具有快表的地址变换机构。访问一次快表耗时1μs,访问一次内存耗时100μs。若快表的命中率为90%,那么访问一个逻辑地址的平均耗时是多少? + +若快表命中,则只用查找一次快表和一次内存,若快表不命中,则要查找一次快表和两次内存。 + +所以(1+100)\*0.9+(1+100+100)*0.1=111μs。 + +若该系统支持快表慢表同时查找,则为(1+100)\*0.9+(100+100)*0.1=110.9μs。 + +#### 两级页表 + +单级页表的缺点: + +1. 单级页表的所有表项都必须连续存储,实现起来比较困难。 +2. 进程在一段时间内只需要访问少数页面就可用正常运行,无需整个页表都常驻内存。 + +将页表进行分组离散地放入内存块,并为离散分组的页表再建立一张页表,称为页目录表、外层页表或顶层页表,页目录表页保存序号和内存块号两项。两级页表结构的逻辑地址结构分为一级页号、二级页号和页内偏移量三项。 + +#### 基本分段存储管理 + +#### 段页式存储管理 ### 内存空间扩充