操作系统 | 内存管理

文章目录

内存的基础知识

在这里插入图片描述

什么是内存?有何作用?

在这里插入图片描述

补充知识:几个常用的数量单位

在这里插入图片描述

回忆:指令的工作原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

装入的三种方式

  • 装入内存,形成【物理地址】
绝对装入

在这里插入图片描述

可重定位装入/静态重定位

在这里插入图片描述

动态运行时装入/动态重定位

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从写程序到程序执行

在这里插入图片描述

链接的三种方式

  • 目标模块链接形成装入模块,链接后形成完整的【逻辑地址】
静态链接

在这里插入图片描述

装入时动态链接

在这里插入图片描述

运行时动态链接

在这里插入图片描述
在这里插入图片描述

内存管理的概念

在这里插入图片描述

内存空间的分配和回收

在这里插入图片描述

内存空间的扩展

在这里插入图片描述

地址转换

在这里插入图片描述
在这里插入图片描述

内存保护

在这里插入图片描述

方式一:上、下限寄存器

在这里插入图片描述

方式二:重定位(基址)寄存器 + 界地址(限长)寄存器

在这里插入图片描述
在这里插入图片描述

覆盖与交换

在这里插入图片描述

覆盖技术

在这里插入图片描述
在这里插入图片描述

  • 由于模块B和模块C在同一时刻内只会有一个被调用,所以我们可以让B和C共享一个覆盖区,覆盖区的大小以B和C之间更大的为准
  • 同样的D、E、F这几个模块也不可能被同时使用,所以几个模块也可以和上面一样共享一个覆盖区,覆盖区的大小以它们中最大的一个为准

交换(对换)技术

  • 中级调度(挂起态)就是为了实现交换技术而使用的一种调度策略
  • 内存空间不足时会把部分进程调到外存,但是调出到外存的进程的PCB仍然常驻内存,因为需要PCB来记录调出外存的进程的具体信息以便后续调入内存

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 对换区的 I/O 速度比文件区的更快
    在这里插入图片描述

连续分配管理方式

在这里插入图片描述

单一连续分配

在这里插入图片描述

固定分区分配

在这里插入图片描述
在这里插入图片描述

动态分区分配

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 本质上我们可以用一句话来概括:在进行内存分区回收的时候,如果回收了之后发现有一些空闲分区是相邻的,那么我们就需要把这些相邻的空闲分区全部给合并
    在这里插入图片描述
  1. 动态分区分配应使用哪种装入方式?
    答:动态重定位。
  2. “紧凑”之后需要做什么处理?
    答:需要把各个进程的起始地址给修改掉,而各个进程的起始地址一般是存在进程的PCB当中,当进程要上CPU运行的时候会把进程的起始地址放到重定位(基址)寄存器里面
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 图中标明大小的内存区域在20MB到来的时候全部成为了外部碎片,可用紧凑/拼凑技术,Compaction 解决外部碎片问题

在这里插入图片描述

在这里插入图片描述

动态分区分配算法

在这里插入图片描述

首次适应算法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

最佳适应算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

最坏适应算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

邻近适应算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 我们只需要按照地址递增的顺序来排列,所以我们在修改完空闲分区链后不需要再把空闲分区链重新排列,这也就是首次适应算法和邻近适应算法比最佳适应算法和最坏适应算法好的一个优点,算法的开销小,不需要花时间对空闲分区链进行重新排列
    在这里插入图片描述
    在这里插入图片描述
  • 如果此时我们采用的是首次适应算法,如果此时需要分配5M的内存空间,那么我们依然需要从链首的位置开始查找,所以前两个不满足,直到第三个才满足,会有3次查找
  • 但是如果我们采用的是邻近适应算法的话,我们只需要从第二个位置开始查找,只需要查2次就好,所以这是邻近适应算法比首次适应算法更优秀的一个地方
  • 首次适应算法会导致低地址部分留下一些比较小的碎片,但是我们每次检索都需要从低地址部分的这些小碎片依次往后检索,所以这就会导致首次适应算法在查找的时候可能会多花一些时间
  • 但这也不意味这邻近适应算法要比首次适应算法要优秀很多

在这里插入图片描述
在这里插入图片描述

基本分页存储管理的基本概念

在这里插入图片描述

什么是分页存储

在这里插入图片描述
在这里插入图片描述

重要的数据结构—页表

  • 页表通常存在PCB(进程控制块)当中
    在这里插入图片描述
    在这里插入图片描述

问题一:每个页表项占多少字节

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题二:如何实现地址的转换

在这里插入图片描述

在这里插入图片描述

子问题:如何确定一个逻辑地址对应的页号、页内偏移量

在这里插入图片描述
在这里插入图片描述

  • 这种规律背后的原理可以联系计算机组成原理无符号左移无符号右移二进制的乘法二进制的除法之间的一个联系

在这里插入图片描述

子问题:为何页面大小要取2的整数幂

在这里插入图片描述

逻辑地址结构

在这里插入图片描述
在这里插入图片描述

基本地址变换机构

  • 基本地址变换机构:基本分页存储管理当中用于实现逻辑地址物理地址转换的一组硬件机构

在这里插入图片描述
在这里插入图片描述

  • 操作系统把内存分为系统区和用户区,系统区中会存放一些操作系统对计算机软硬件进行管理的一些相关的数据结构,包括进程控制块PCB

  • 如果进程被调度,上处理机运行,进程切换相关的内核程序就会把进程的运行环境给恢复,这些进程运行环境相关的信息是保存在PCB当中的,上处理机之后进程运行环境的相关信息会被放到一些相应的一些寄存器当中,包括页表寄存器,里面存放着这个进程页表的起始地址和页表的长度

  • 另外的比如程序计数器PC也是需要恢复的,指向下一条指令的逻辑地址

  • 在分页管理系统中,逻辑地址表示的页号和页内偏移量的位数操作系统都是知道的,只要得到了逻辑地址就能很快地切分出页号和页内偏移量这两个部分

  • 接下来系统会对页号的合法性进行检查,如果此时页号【等于或者已经超出】了页表长度(表明的是这个页表总共有多少个页表项)的话,系统就会认为此时所要访问的逻辑地址是非法的,此时会抛出一个越界中断(内中断)

  • 为什么页号等于页表长度的时候也会产生越界中断呢?因为页号是从0开始的,而页表长度至少是1,所以假如一个进程的页表长度是1,那么它的页号最大只应该是0,如果想要访问页号为1的那个页面,其实就应该已经发生越界了,所以页号等于页表长度的时候也是会产生越界中断的

  • 如果页号是合法的,那么会把页号和页表起始地址进行一个计算,找到这个页号所对应的页表项是多少,页表当中的每一个页表项的长度都是相同的,所以我们只要知道了页号和页表起始地址,再知道每个页表项的长度,我们就可以算出我们所要访问的页号对应的页表项所存放的位置

  • 此时我们再用所得到的内存块号结合页内偏移量就可以当得到最终的物理地址,然后就可以顺利地访问逻辑地址A所对应的内存单元了
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 注意不要忽略对页号进行越界检查的这一步操作

对页表项大小的进一步探讨

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

具有快表的地址变换机构

在这里插入图片描述

什么是快表TLB

  • TLB 不是内存!而是一种访问速度比内存快很多的高速缓存

在这里插入图片描述
在这里插入图片描述

能否把整个页表都放在TLB中?

在这里插入图片描述

快表是如何工作的?

在这里插入图片描述

  • 这里要访问的逻辑地址(M,N)前面的M表示的是页号,后面的N表示的是页内偏移量
  • 当进程上处理机运行的时候系统会清空快表TLB的内容(当进程切换的时候快表的内容也需要被清除)
  • 首先进程想要访问的是页号为0,页内偏移量也为0的逻辑地址,页号0首先会和页表寄存器的页表长度进行越界异常的检查,发现页号并没有越界,然后就会查询快表,但是由于进程刚上处理机运行,因此快表此时的内容为空,在快表中找不到页号为0所对应的页表项,因此快表没有命中,快表没命中所以不得不访问内存中存放的慢表,所以接下来通过页表始址和页号计算出对应的页表项存放的位置,于是在查询完慢表之后可以知道0号页面它所存放的内存块号是600,(注意如果快表没有目标页表项,在访问这个页表的页表项之后,需要把这个页表项放入快表),然后根据内存块号和页内偏移量就可以得到最终的物理地址,最后就可以访问这个逻辑地址所对应的内存单元了
  • 接下来这个进程想要访问的是页号为0,页内偏移量为4的逻辑地址,同样的刚开始会进行一个越界异常的判断,发现没有越界,接下来会根据页号来查询快表,需要确认一下这个页号所对应的页表项是否在快表当中,由于刚才我们已经把他们复制到了快表当中,因此这一次的查询就可以命中,而快表命中之后系统就可以直接知道0号页面它存放的内存块号是600,因此接下来就不需要查询内存当中的慢表,而是直接根据内存块号和页内偏移量得到最终想要得到的物理地址,然后进行访存,因此快表命中的话就不需要访问内存当中的慢表了
  • 接下来这个进程想要访问的是页号为0,页内偏移量为8的逻辑地址,同样的刚开始会进行一个越界异常的判断,发现没有越界,接下来会根据页号来查询快表,需要确认一下这个页号所对应的页表项是否在快表当中,由于刚才我们已经把他们复制到了快表当中,因此这一次的查询就可以命中,而快表命中之后系统就可以直接知道0号页面它存放的内存块号是600,因此接下来就不需要查询内存当中的慢表,而是直接根据内存块号和页内偏移量得到最终想要得到的物理地址,然后进行访存,因此快表命中的话就不需要访问内存当中的慢表了

引入快表之后,地址变换的过程

在这里插入图片描述

在这里插入图片描述

局部性原理

在这里插入图片描述
在这里插入图片描述

二级页表

在这里插入图片描述

单级页表存在的问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如何解决单级页表的问题?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

两级页表的原理及地址结构

在这里插入图片描述
在这里插入图片描述

如何实现地址变换

在这里插入图片描述

需要注意的几个细节

在这里插入图片描述

  • 没有快表机构的话,n级页表在访问一个逻辑地址的时候,访存次数应该是n+1次
    在这里插入图片描述

基本分段存储管理方式

在这里插入图片描述

分段

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

段表

在这里插入图片描述

地址变换

在这里插入图片描述
在这里插入图片描述

  • 在内存的系统区当中存放着很多用于管理系统当中软硬件资源的数据结构,包括进程控制块PCB也是存放在系统之中的
  • 当一个进程要上处理机运行之前,进程切换相关的内核程序会把进程的运行环境给恢复,这就包括一个很重要的硬件寄存器的数据的恢复——段表寄存器,用于存放这个进程的段表在内存当中的起始地址还有这个进程的段表长度到底是多少,因此段表在内存当中的起始地址还有这个进程的段表长度在进程还没上处理机之前是存放在内存的PCB当中的,当进程上处理机运行的时候这两个信息会被放到读取速度很快的段表寄存器当中,知道段表起始地址之后就可以知道段表被放在内存中的什么地方了
  • 进程运行的过程中如果要访问逻辑地址A,那么系统会根据逻辑地址得到段号S和段内地址W
  • 知道了段号之后需要把段号S和段表长度M进行对比来判断一下段号是否产生了越界,若S≥M,则产生越界中断,否则继续执行,注意这里段号是从0开始的,而段表长度至少为1
  • 如果没有越界,则会根据段号和段表始址来查询段表,找到这个段号对应的段表项,由于各个段表项的大小是相同的,所以用段表始址+段号×段表项长度就可以找到我们的目标段对应的段表项在内存当中的位置了,接下来就可以读出段表项的内容
  • 找到了段号所对应的段表项之后,系统还会对段内地址W做一个检查,看看它是否已经超过了这个段的最大段长C,如果W≥C则产生越界中断,否则继续执行
  • 此时我们已经找到了目标段的段表项,所以我们知道目标段存放在内存中的什么地方,最后我们根据这个目标段的基址+最终要访问的段内地址就可以得到我们最终想要得到的物理地址了
  • 着重需要关注的是在分段和分页的不同:分页当中每个页面的长度是相同的,而分段当中每个段的长度是不同的,所以在分页管理当中并不需要对页内偏移量做越界管理的检查,但是在分段管理当中我们一定需要对段内偏移量和段长进行一个越界检查

分段、分页管理的对比

在这里插入图片描述

  • 分段比分页【更容易实现信息的共享和保护】
    在这里插入图片描述

  • 如果我们要实现共享的话只需要各个进程的某一个段表项指向同一个段就可以了
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

段页式管理方式

在这里插入图片描述

分页、分段的优缺点分析

在这里插入图片描述

在这里插入图片描述

段页式管理 = 分段 + 分页

在这里插入图片描述

段页式管理的逻辑地址结构

在这里插入图片描述

段表、页表

在这里插入图片描述

  • 一个进程只会对应一个段表,但是每个段会对应一个页表,因此一个进程有可能对应多个页表

段页式管理逻辑地址到物理地址转换的实现

在这里插入图片描述

  • 系统当中也会有一个段表寄存器这么一个硬件,在进程上处理机运行之前会从PCB当中读出段表始址和段表长度这些信息放到段表寄存器当中
  • 根据逻辑地址得到段号、页号和页内偏移量
  • 段号S和段表长度M进行一个对比,检查段号是否越界、是否合法,若S≥M则产生越界中断,否则就继续执行
  • 根据段号和段表始址,查询段表,计算出段号所对应的段表项在内存当中的位置,这样的话就找到了我们要找的段表项
  • 接下来需要注意,由于各个段的长度是不一样的,所以各个段进行分页之后有可能被分为数量不等的不同页面,因此我们需要对页号的合法性进行检查,检查页号是否已经越界,若页号≥页表长度,则发生越界中断,否则继续执行
  • 根据页表存放块号和页号查询页表,找到对应的页表项并根据内存块号、页内偏移量得到最终的物理地址
  • 访问目标内存单元

在这里插入图片描述

  • 用户只需要提供段号和段内地址的信息,所以段页式管理也是二维的

虚拟内存的基本概念

在这里插入图片描述
在这里插入图片描述

传统存储管理方式的特征及缺点

在这里插入图片描述

局部性原理

在这里插入图片描述

虚拟内存的定义和特征

在这里插入图片描述
在这里插入图片描述

如何实现虚拟内存技术

在这里插入图片描述
在这里插入图片描述

请求分页管理方式

在这里插入图片描述

页表机制

在这里插入图片描述

缺页中断机构

在这里插入图片描述

  • 此时想要访问的逻辑地址刚好指明了要访问0号页面,对应外存中的x号块,而内存中恰好a号块空闲,则为进程分配一个空闲块,把外存中x号块装入到a号块的位置进行访问,并修改页表中相应的页表项
    在这里插入图片描述
  • 如果此时内存中没有空闲块,需要由页面置换算法通过某种规则选择淘汰一个页面,比如说此时选中了要淘汰2号页面,由于2号页面此时的修改位为1,表明2号页面是被修改过的,所以2号页面的内容需要从内存写回外存,把外存中的旧数据给覆盖掉,这样的话2号页面所占有的c号块就可以空出来让0号页面使用了,于是就可以把0好页面从外存调到内存当中,相应的我们需要把换出外存的和换入内存的页面的相应数据给更改
    在这里插入图片描述
  • 缺页中断 - 内中断 - 故障 fault

地址变换机构

在这里插入图片描述
在这里插入图片描述

  1. 检查页号的合法性,看下页号是否越界
  2. 如果页号没有越界就查询快表,看有没有这个页号所对应的页表项,如果快表命中就可以得到最终的物理地址
  3. 需要注意的是快表中有的页面一定是在内存中的,如果某个页面被换出外存,则快表中相应的表项也要被删除,否则可能访问到错误的页面
  4. 如果快表没有命中的话就需要查询内存当中的慢表,找到对应的页表项之后,查询此时页面是否已经调入内存
  5. 如果页面此时没有在内存中,则缺页中断机构会产生一个缺页中断的信号,之后就会由操作系统的缺页中断处理程序进行处理,包括调页还有页面置换等一些列的事情,当页面调入之后也需要修改页表项所对应的一些数据
  6. 形成物理地址

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

页面置换算法

  • 在内存空间不够的时候,在一些内存中暂时用不到的页面中选择一个换出内存

在这里插入图片描述

最佳置换算法OPT

在这里插入图片描述
在这里插入图片描述

  • 缺页中断未必发生页面置换,比如前面页面还没满时发生缺页但是没有页面置换,只有当内存块已经都满了的时候才会发生页面置换
    在这里插入图片描述
  • 理想化算法,实际运用中无法实现

先进先出置换算法FIFO

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最近最久未使用置换算法LRU

  • Least Recently Used
    在这里插入图片描述
    在这里插入图片描述

  • 最近最久未使用的性能是最接近最佳置换算法的,但是实现起来需要专门的硬件支持,算法开销大

时钟置换算法CLOCK

  • 时钟置换算法,CLOCK算法,最近未用算法(NRU,Not Recently Used)
    在这里插入图片描述
简单的CLOCK时钟置换算法

在这里插入图片描述

  • 由于系统为进程分配了5个空闲的内存块,所以前5个内存块1、3、4、2、5会被顺利地放入内存,只有轮到6号页的时候才会考虑淘汰某个页面,其中1、3、4、2、5这5个页面通过链接指针的方式形成一个循环队列

在这里插入图片描述

  • 当来到第6个页面的时候内存块已经满了,所以需要用CLOCK算法选择一个页面进行淘汰置换,会从队首进行扫描,尝试找到首个访问位为0的页面,并且被扫描过的页面需要把访问位从1改为0

在这里插入图片描述

  • 在经过第一轮的访问之后,所有页面的访问位都由1变为了0
  • 那么在进行第二轮的扫描的时候,第一个访问到的1号页的访问位为0,所以会选择淘汰1号页,于是6号页会分配到1号页以前占有的内存块当中,并且6号页的访问位会被置为1,然后扫描的指针指向下一个页面

在这里插入图片描述

  • 接下来的访问会访问到3号和4号页面,在访问完3号页面的时候,3号页面的访问位需要由0变为1,同样的在访问完4号页面的时候,4号页面的访问位需要由0变为1
  • 【注意这里访问的时候是直接访问并修改访问位,指针是不需要移动的!这里的页面都在内存中可以直接访问,指针扫描的目的是为了找到符合替换条件的页面替换出去,所以只有当需要页面替换的时候才需要移动指针】

在这里插入图片描述

  • 再之后需要访问7号页,由于此时7号页没有在内存中,所以需要选择淘汰其中的某一个页面,然后把7号页放到内存当中,同样的需要从此时扫描到的位置依次扫描找到第一个访问位为1的页面,并且扫描过的页面的修改位需要由1变为0,所以3、4号在扫描过后访问位会变为0

在这里插入图片描述

  • 由于2号页面此时的访问位就是0了,于是淘汰2号页面,由7号页替换2号页面,然后扫描的指针指向下一个页面

在这里插入图片描述

改进的CLOCK时钟置换算法

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 假设系统为内存分配了5个内存块,那当这个内存块被占满之后,各个页面会用这种链接的方式连成一个循环队列
  • 此时如果需要淘汰一个页面的话,需要从这个队列的对头开始依次地扫描
  • 那根据改进型的时钟置换算法的规则,在第一轮的扫描当中,并不修改任何的标志位,需要尝试找到访问位和修改位都为0的页面(0,0),依次往后寻找(0,0)页面,此时是能找到的,替换其即可
    在这里插入图片描述
  • 再来看下一种情况,假设系统为内存分配了5个内存块,那当这个内存块被占满之后,各个页面会用这种链接的方式连成一个循环队列
  • 此时如果需要淘汰一个页面的话,需要从这个队列的对头开始依次地扫描
  • 那根据改进型的时钟置换算法的规则,在第一轮的扫描当中,并不修改任何的标志位,需要尝试找到访问位和修改位都为0的页面,依次往后寻找(0,0)页面
    在这里插入图片描述
  • 第一轮扫描下来发现都不满足(0,0)这样的状态,因此会进行第二轮的扫描,第二轮扫描会尝试找到原本状态就是(0,1)的这样的一个页面,并且扫描过的页面会把访问位置为0
    在这里插入图片描述
  • 再来看下一种情况,假设系统为内存分配了5个内存块,那当这个内存块被占满之后,各个页面会用这种链接的方式连成一个循环队列
  • 此时如果需要淘汰一个页面的话,需要从这个队列的对头开始依次地扫描
  • 那根据改进型的时钟置换算法的规则,在第一轮的扫描当中,并不修改任何的标志位,需要尝试找到访问位和修改位都为0的页面,依次往后寻找(0,0)页面
    在这里插入图片描述
  • 第一轮扫描下来发现都不满足(0,0)这样的状态,因此会进行第二轮的扫描,第二轮扫描会尝试找到原本状态就是(0,1)的这样的一个页面,并且扫描过的页面会把访问位置为0
    在这里插入图片描述
  • 第二轮扫描下来发现都不满足(0,1)这样的状态,因此会进行第三轮的扫描,第三轮扫描会尝试找到原本状态就是(0,0)的这样的一个页面,但是并不修改任何标志位
    在这里插入图片描述
  • 再来看下一种情况,假设系统为内存分配了5个内存块,那当这个内存块被占满之后,各个页面会用这种链接的方式连成一个循环队列
  • 此时如果需要淘汰一个页面的话,需要从这个队列的对头开始依次地扫描
  • 那根据改进型的时钟置换算法的规则,在第一轮的扫描当中,并不修改任何的标志位,需要尝试找到访问位和修改位都为0的页面,依次往后寻找(0,0)页面
    在这里插入图片描述
  • 第一轮扫描下来发现都不满足(0,0)这样的状态,因此会进行第二轮的扫描,第二轮扫描会尝试找到原本状态就是(0,1)的这样的一个页面,并且扫描过的页面会把访问位置为0
    在这里插入图片描述
  • 第二轮扫描下来发现都不满足(0,1)这样的状态,因此会进行第三轮的扫描,第三轮扫描会尝试找到原本状态就是(0,0)的这样的一个页面,但是并不修改任何标志位
  • 第三轮扫描下来发现都不满足(0,0)这样的状态,因此会进行第四轮的扫描,第四轮扫描会尝试找到原本状态就是(0,1)的这样的一个页面,但是并不修改任何标志位
    在这里插入图片描述
    在这里插入图片描述

页面分配策略

在这里插入图片描述

页面分配与置换策略

在这里插入图片描述
在这里插入图片描述

  • 为什么多道程序并发度下降会使系统的某些资源利用率降低呢?
  • 比如像CPU和I/O设备这样的两种资源理论上是可以并行工作的,如果多道程序并发度下降,则CPU和I/O设备这样的两种资源并行工作的几率就会小很多,所以资源的利用率就会有所降低

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 系统会锁定一些很重要的不允许被换出外存需要常驻内存的页面,比如说系统当中的某些很重要的内核数据可能是会被锁定的

在这里插入图片描述
在这里插入图片描述

何时调入页面

在这里插入图片描述

从何处调入页面

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

抖动(颠簸)现象

在这里插入图片描述

工作集

在这里插入图片描述
在这里插入图片描述

内存映射文件

在这里插入图片描述

内存映射文件 Memory-Mapped Files

在这里插入图片描述

方便程序员访问文件数据

传统的文件访问方式

在这里插入图片描述

  • 上面是一个文件,名字叫操作系统.txt,这个文件存放到磁盘里边
  • 磁盘的存储空间是以块为单位的,这样的1块大小是1KB,相应的这个文件就会被拆分成几个大小相等的块,每个块刚好是1KB,刚好可以放到这个磁盘里面
  • 那这些块有可能被离散地存放到磁盘的各个角落
    在这里插入图片描述
  • 如果一个进程想要访问这个文件的数据,传统的做法是:
  • 首先每个进程都有自己的虚拟地址空间
    在这里插入图片描述
  • 如果这个进程想要访问这个文件的数据,首先需要使用open系统调用来指明打开这个文件
  • 接下来需要使用seek系统调用,将读写指针移到某个位置,来指明它想要读取这个文件的哪部分数据,操作系统会用一个读写指针来记录
  • 接下来进程可以使用read系统调用来指明从当前读写指针的位置往后它想要读入多少字节的数据(从磁盘读入内存)
  • 如果进程要读入的这部分数据刚好是存放在文件的第二个块这里,那么接下来操作系统就会把这一块的数据给读入内存,那么进程就可以去访问内存里的这一部分数据了
  • 当然进程也可以修改这一部分的数据,如果想要使修改被保存,那么进程还需要使用write系统调用把内存里的这一块数据写回磁盘
内存映射文件

在这里插入图片描述

  • 如果一个系统支持内存映射文件的功能,那么一个程序员或者一个进程访问文件的方式就会变得更简单
  • 首先需要使用open系统调用指明打开一个文件
  • 接下来使用mmap系统调用,让操作系统把文件映射到进程的虚拟地址当中
    在这里插入图片描述
  • mmap系统调用会给程序员返回一个指针,这个指针会指向刚才映射的这片区域的起始地址
  • 接下来程序员就可以用访问内存的方式去访问这些文件数据了,如F[1]、F[2]…,这个指针可以访问到这个文件的任何一个数据
  • 图中的文件3个块在进程虚拟地址空间是灰色的,原因是在使用了mmap系统调用之后,操作系统只是建立了文件数据和内存之间的一个映射关系,但是并没有把文件数据直接读入内存,处于一个缺页的状态
  • 假定此时你要访问的数据刚好是在文件的第2块
    在这里插入图片描述
  • 操作系统会发现这一块的数据还没有被调入主存,出现了一个缺页异常,此时操作系统会自动地把这一块的数据给读入内存,同样的如果你此时还想访问第3块数据,而第3块数据此时还处于缺页的状态的话,操作系统会自动地帮你把第3块数据搞到内存里
  • 我们作为程序员我们不需要自己再去调用read函数,读入数据的过程是由操作系统自动帮我们完成的,然后就可以对内存中的数据进行读取或者写入操作了
  • 如果进程不再需要使用这个文件,进程可以用close系统调用来关闭文件,当关闭文件之后操作系统会自动地把文件当中被修改的数据给写回磁盘
    在这里插入图片描述
  • 采用内存映射文件之后,程序员对这个文件数据的访问就方便多了,程序员只需要知道这个文件在内存当中的起始地址,接下来按照访问内存的方式去访问这个文件当中的数据就可以,文件数据的读入或者写出都是由操作系统自动来完成的
  • 相比之下传统的文件访问方式需要程序员自己去调用read系统调用和write系统调用,才可以读入或者写出文件的数据,所以内存映射文件可以让程序员更方便的使用文件数据
    在这里插入图片描述

方便多个进程共享一个文件

  • 文件可以被进程用系统调用的方式映射到自己的虚拟地址空间里,同样的另一个进程也可以把这个文件映射到自己的虚拟地址空间里
  • 此时两个进程的虚拟地址空间是相互独立的,但是操作系统会把这两块虚拟地址空间映射到相同的物理内存上,操作系统只需要修改这两个进程的页表,让对应的页面映射到相同的物理页框上就可以让两个进程实际上是在共享同一份文件的数据
  • 在这样的情况下当一个进程修改了文件的数据之后,另一个进程也就可以立刻看到这一块文件数据的改变
    在这里插入图片描述
    在这里插入图片描述
  • 什么时候要读入一个文件的数据块,什么时候要写出一个文件的数据块,完全是由操作系统控制的
  • 这么做的好处在于操作系统可以通过某些策略去优化磁盘I/O的效率,如预读入缓写出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ErizJ

觉得好的话给小弟一点鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值