虚拟内存

虚拟内存

概述

  • 定义:利用 ==按需调页== 和 ==页面置换== 技术在 ==逻辑上== 对物理内存进行 ==扩大== 的技术

  • 核心:按需调页 + 页面置换

  • 解释:

    • 程序在加载进入内存中时,仅将程序的 需要使用的页 装入内存,而将 暂时不需要使用的页留在后备存储中

      处理器再执行程序中的指令时,访问的部分没有被加载进入内存中,此时将这部分程序加载进入内存中 -> 按需调页

    • 空闲内存低于阈值时,会将内存中 暂时没有使用页换出 到后备存储的 交换空间 中,换入 当前处理器 需要访问的页 -> 页面置换

    • 因为不断地换入换出进程的页面,用户就会感觉进程 整个 都在内存中运行,就好像使用了比实际物理内存更大内存,也就是虚拟内存

      虚拟内存技术可以说就是制造“假象”的技术

    cf892cbdfc01d5b16b3d8da015844a66.png
  • 举例:在线观看视频

    • 浏览器并不会将整个视频全部传输完成再播放,那样显然就变成下载了;

    • 浏览器每播放一部分就下载一部分,播放过的部分就会被正在播放的部分直接覆盖;

    • 用户需要倒推观看时会发现仍然需要缓冲(除非网速很快),因为之前观看的部分已经被删除了;

    • 这样给用户的感觉就是整个视频都被加载到内存中播放,但实际上仅仅用了很少的内存

  • 特点:

    • 多次性:不需要一次性将程序的所有页全部加载进入内存
    • 对换性:允许进程的页在运行过程中换出内存进入交换空间
    • 虚拟性
  • 实现:

    • 基于 ==分页式== 的内存管理
    • 基于 ==分段式== 的内存管理
    • 基于 ==段页式== 的内存管理
  • 细节:

    • 虚拟内存称呼:

      • 虚拟内存技术:内存管理的一种技术,并不是指的某个具体存储空间

      • 虚拟内存空间(交换空间):硬盘等外部存储设备利用部分存储空间存储临时性的虚拟地址,这里指的就是实际存在的存储空间,也被称为交换空间

        注:这两个概念通常都被简称为虚拟内存,实际代表什么需要根据上下文语境来查看

    • 虚拟内存查看:

      windows: systeminfo 指令可以查看虚拟内存情况

c5cf9fe08fb4d27f3d7a0b714dd1126f.png

请求调页

概述

76f455f3e5b40584b68cea4eb9db2fcd.png

页错

  • 定义:进程试图访问没有被调入内存的页面时产生的错误

    注:不能够说进程试图访问有效-无效位为无效的页面时产生的错误:==没有被调入内存 ≠ 有效-无效位为无效==

  • 分类:

    • 进程访问的页确实是无效的 -> 系统就没计划为其分配内存,产生页错

    • 进程访问的页面是有效的 -> 系统计划为其分配内存但是并没有真正分配,产生页错

      解释:这种情况的出现主要是由于程序员声明了分配内存,但是暂时还没有使用这块内存,所以系统不会为其真正分配内存

  • ==处理==:

    f57e06381954a1a3882b51ec2fae42dd.png
    1. 操作系统执行 陷阱处理 程序

    2. 调度程序 保存进程上下文(进程的程序计数器,进程状态…)

    3. 开始处理中断:判断中断是否为 缺页中断

      (1) 如果是缺页中断: 调入相应的页进入空闲帧

      注:如果帧表中存在空闲帧,那么直接调入就行;如果帧表中不存在空闲帧,那么需要使用 页面置换,换出暂不使用的页,换入需要使用的页

      (2) 如果是越界中断:直接终止进程

    4. I/O 系统控制磁盘读取相应的页:

      (1) 调度程序执行上下文切换:进程进入设备队列等待running -> waiting

      (2) 等待磁盘的的寻道时间(查询数据的时间)

      (3) 磁盘查询到相应数据开始传输数据

    5. 调度程序将处理器 分配给其余需要使用的进程

    6. I/O 系统在磁盘传输完成后 发出中断

    7. 调度程序 保存进程上下文

    8. 确定中断来自于磁盘并且开始处理中断

    9. 更新页表 及其相关信息 (waiting -> ready

    10. 调度程序再次执行上下文切换

    11. 重新将处理器分配给该进程并且 重新执行指令

  • 性能分析:

  • 细节:

页面置换

概述

  • 前提:内存中已经 没有空闲帧 用于存放新加载进入内存的页面

    • 解决方式:(1) 终止当前需要调页的进程 (2) 换出 其他进程释放空间 (3) 页面置换
  • 定义:

    • 调度程序选择 ==牺牲帧== 并将其 ==换出== 到后备存储的 ==交换空间== 中
    • 调度程序再将 需要使用的帧 换入(加载)进入内存的 ==空闲帧== 中
  • 分类:

  • 处理过程:

    1. 内存管理单元根据 页表 确定需要使用的 页面的磁盘地址

    2. 调度程序寻找 空闲帧

      • 内存中存在空闲帧:随机选择某个空闲帧存放页面(优先

      • 内存中不存在空闲帧:利用 页面置换算法 选择 牺牲帧 将其换出到 交换空间 中腾出空闲帧存放页面

        牺牲帧并不一定需要换出到交换空间:只要牺牲帧没有被修改过就不需要

    3. 内存管理单元 修改帧表和页表

    4. 从发生缺页错误的位置继续执行进程

  • 修改位(脏位)

    • 定义:用于标记页面是否被 ==修改== 过

    • 功能:用于 ==减少== 页面置换时产生的换入换出 ==开销==

      解释:如果页面没有被修改过,那么就不需要再将其换出到交换空间中,因为和磁盘存储的页面是一样的;如果页面修改过,就需要将其换出到交换空间中

  • 细节:

置换算法

  • 前提:下列所有算法都是 基于局部替换策略

  • 内存引用串:

    • 定义:处理器一段时间内需要访问的 页号序列

      举例:逻辑地址序列 101 114 514 223 233 页面大小 100 -> 内存引用串:1 1 5 2 2

    • 计算方式:

      • 10 进制逻辑地址:逻辑地址 ÷ 页面大小 = 页号 + 偏移量

      • 2 进制逻辑地址:

        • 方法一:2进制逻辑地址转换为10进制逻辑地址再算
        • 方法二:(1) 2进制逻辑地址的比特位个数 - 表示页面大小需要的比特位个数 = 表示页号需要的比特位个数 (2) 再将2进制的页号转为10进制

        举例:2进制逻辑地址:10110011 页面大小 15:相当于是最低 4 位表示 ???

  • 算法评判标准:帧错误率尽可能低

  • 细节:进程被分配的物理帧越多帧错误率会越低

FIFO 置换算法

  • 定义:每次选择 ==最早进入== 内存的页面进行替换

  • 实现:利用 队列 记录页面进入内存的“时间”:并不记录具体的时间

    解释:最早进入内存的页面就是队首元素,后续进入的页面依次进入队列;

    ​ 每次页面置换的时候就选择队首元素替换,然后让队列第二个元素称为队首元素,新的页面称为队尾元素

  • 优点:实现最为简单

  • 缺陷:(1) 产生 ==Belady异常==:随着进程被分配的 物理帧数的增加缺页错误的数量也增多 (2) 性能 最差

OPT 置换算法

  • 定义:每次选择那些在 ==未来 长时间不使用== 的页面进行替换
  • 优点:具有 最优 的性能
  • 缺点:几乎不能实现(解释:不可能预测到哪些页面将会在未来访问)

LRU 置换算法

  • 定义:每次选择那些在 ==过去 长时间不使用== 的页面进行替换
  • 实现:
    • 计数器实现
      1. 每个页面维护一个计数器
      2. 每次页面被访问时该页面的计数器就递增
    • 堆栈实现
      1. 堆栈中保存当前 使用过 的页号
      2. 堆栈中的页号每次被引用时都从栈中移除然后 压入栈顶;不存在于堆栈的页号被引用时 直接压入栈顶
      3. 确保堆栈的 顶端 是最近访问的页面,堆栈的 底端 是长时间没有访问页面
  • 细节:
    • 两种实现方式都属于 堆栈算法,绝对不会产生 Belady 异常
    • 采用这两种实现方式的 LRU 算法也被称作标准 LRU 算法:是不可能实现的

页置换算法

近似 LRU 置换算法

  • 额外引用位算法

    1. 每个页面都必须维护一个 ==8位 的移位寄存器==:表示为 $R = R_7R_6···R_2R_1R_0$(表示寄存器的位数)

    2. 每次访问某个页面时都将该页面的移位寄存器中的 ==R7 位置为 1==

    3. 每隔一定的时间移位寄存器中就会 ==右移一位==,最低位直接 ==抛弃==

      举例:时钟信号发出,移位寄存器右移,R3 = R4 = 1,其余位置一样

    4. 最后选择 ==寄存器数值最小== 的作为长时间没有访问页面

      举例:页面 0 寄存器:11001100; 页面 1 寄存器:00110101 ;页面 2 寄存器 00010111 -> 显然页面 2 是寄存器数值最小的页面

    注:可能同时多个页面的寄存器数值一样大:(1) 可以全部替换 (2) 可以使用 FIFO 在这些页面当中选择

  • 第二次机会算法:

    1. 每个页面仅维护 ==1位== 的引用位;并且将所有页面以 ==循环队列== 的方式维护
    2. 每次替换页面时就在循环队列中查找:(1) 如果引用位为 0 就直接替换该页面 (2) 如果引用位为 1 就继续循环查找并将当前页面的引用位置为 0(二次机会)

    注:最坏的情况是每页的引用位都是 1:那么该算法将会将所有的引用位重新置为 0 再进行循环查找 (相当于退化成 FIFO 算法)

基于计数的置换算法

  • 最不常使用算法
  • 最常使用算法
Author: Fuyusakaiori
Link: http://example.com/2021/09/18/os/memory/虚拟内存/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.