目录

操作系统之存储管理(二)

存储管理器: 管理分层存储器体系 用于管理内存

无存储器抽象

直接访问物理内存 0->上限地址的集合 每个地址容纳8个二进制的存储单元

只有OS和一个用户进程下 组织内存的3个简单方法

  1. OS位于RAM底部 可能摧毁OS
  2. OS位于ROM顶部
  3. 设备驱动程序位于内存顶端的ROM中 OS其他部分位于下面RAM的底部 可能摧毁OS

不使用内存抽象情况下 仍是能运行多道程序 当要运行别的程序时 先保存当前内存的所有内容 然后切换 其他程序 早期模型中给内存设有保护键 (4位) PSW(程序状态字)有1个4位码 若进程要访问保护键和其PSW码不同的内存 硬件就能捕捉到 只有OS才能修改保护键

同时还有一个缺陷:装载2个程序 程序访问的是绝对物理地址 会造成访问到别的程序的内容的情况 使用静态重定位可以解决 但不是通用的方法

地址空间: 存储器的抽象

保证多个程序处于内存且不会互相影响 要解决两个问题

  1. 保护
  2. 重定向

上面的保护键 解决了保护问题 但对于重定位问题是比较的缓慢且复杂

更好的办法是创建新的内存抽象: 地址空间 地址空间创建了抽象的内存

地址空间: 一个进程可用于寻址内存的一套地址集合

但让A程序的地址对应的物理地址空间与B程序对应的物理空间不同是比较难的

基址寄存器和界限寄存器

动态重定位

  • 基址寄存器: 存放起始物理地址
  • 界限寄存器: 程序的长度

上面的两个寄存器给每个进程提供私有地址空间 且为了提供保护 只有OS能够修改他们 缺陷是每次访问需进行加法比较运算

交换技术

OS启动时候加载进程是很多的 遇到内存超载情况 可以使用

交换技术

完整调入内存 运行一段时间 再存回磁盘

虚拟内存

使程序在只有一部分被调入内存的情况下运行

内存紧缩: 将空余区合成一大块

进行内存分配的时候 如果进程创建时大小是固定的 比较容易 但进程的数据段 会出现增长

为了方便则可以分配额外的内存 交换出去的时候只交换实际上使用的内存的内容

空闲内存管理

2种方式跟踪内存使用情况

  1. 位图 几个字或几千个字节为分配单元
  2. 空闲链表 空间区: 开始地址: 长度

按照地址顺序在链表中存放进程和空闲区时 可以使用几种算法来分配内存

以存储管理器知道要为进程分配多大内存为前提

  • 首次适配算法

除非空闲区和要分配的大小一样 否则分为2部分 1部分供进程 一部分供空闲区

  • 下次适配算法

找到合适位置时候记录当时位置 以便下次继续搜索 但这个算法性能略低于上面的算法性能

  • 最佳适配

遍历整个链表 找到能容纳进程的最小空闲区 但会产生大量无用的小空闲区

  • 最差适配

总是分配最大的可用空闲区 使得新的空闲区比较大从而可以继续使用

虚拟内存

如今 需要运行的程序 大到内存无法容纳 交换技术也不是很有效的方案 以前是通过使用覆盖技术 即把程序分割为许多片段

程序运行时 管理模块立即装入并允许覆盖0 0执行完成后 通知1 但这是十分的繁琐并且容易出错的

于是就使用虚拟内存

每个程序拥有自己地址空间 空间被分割为多个块 每个块叫做 每个页有连续的地址范围 页被映射到物理内存 部分页在内存中也可以运行 程序引用到物理内存的地址空间时 硬件执行映射 引用到不再物理内存中的地址空间时 OS负责装入缺失的部分

分页

虚拟地址为程序产生的地址 构成了虚拟地址空间

  • 没有虚拟内存的计算机 系统直接将虚拟地址送到内存总线
  • 有虚拟内存的计算机 先送到MMU(内存管理单元)进行映射

设置MMU 可以将16个虚拟页面映射到8个页框(物理内存对应单元) 有8个没有映射

如果MMU映射的是无映射的 则称为缺页中断 OS找一个使用较少的页框 去修改它 将之前无映射的页面读到页框 修改映射关系

页表

虚拟地址被分为虚拟页号 偏移量

页表项可以找到页框号 页框号拼接到偏移量的高位端 替换掉虚拟页号

虚拟页号作为页表索引 找到虚拟页面的页表项 页表项找到页框号

页表项的细节

  1. 页框号
  2. 在/不在位
  3. 保护位 允许什么样的访问
  4. 修改位
  5. 访问位
  6. 禁止高速缓存位

加速分页过程

分页式系统中 要考虑2个问题

  1. 虚拟地址到物理地址的映射必须快
  2. 虚拟地址空间很大 页表也会很大