目录
操作系统之存储管理(二)
存储管理器: 管理分层存储器体系 用于管理内存
无存储器抽象
直接访问物理内存 0->上限地址的集合 每个地址容纳8个二进制的存储单元
只有OS和一个用户进程下 组织内存的3个简单方法
- OS位于RAM底部 可能摧毁OS
- OS位于ROM顶部
- 设备驱动程序位于内存顶端的ROM中 OS其他部分位于下面RAM的底部 可能摧毁OS
不使用内存抽象情况下 仍是能运行多道程序 当要运行别的程序时 先保存当前内存的所有内容 然后切换 其他程序 早期模型中给内存设有保护键 (4位) PSW(程序状态字)有1个4位码 若进程要访问保护键和其PSW码不同的内存 硬件就能捕捉到 只有OS才能修改保护键
同时还有一个缺陷:装载2个程序 程序访问的是绝对物理地址 会造成访问到别的程序的内容的情况 使用静态重定位可以解决 但不是通用的方法
地址空间: 存储器的抽象
保证多个程序处于内存且不会互相影响 要解决两个问题
- 保护
- 重定向
上面的保护键 解决了保护问题 但对于重定位问题是比较的缓慢且复杂
更好的办法是创建新的内存抽象: 地址空间 地址空间创建了抽象的内存
地址空间: 一个进程可用于寻址内存的一套地址集合
但让A程序的地址对应的物理地址空间与B程序对应的物理空间不同是比较难的
基址寄存器和界限寄存器
动态重定位
- 基址寄存器: 存放起始物理地址
- 界限寄存器: 程序的长度
上面的两个寄存器给每个进程提供私有地址空间 且为了提供保护 只有OS能够修改他们 缺陷是每次访问需进行加法和比较运算
交换技术
OS启动时候加载进程是很多的 遇到内存超载情况 可以使用
交换技术
完整调入内存 运行一段时间 再存回磁盘
虚拟内存
使程序在只有一部分被调入内存的情况下运行
内存紧缩: 将空余区合成一大块
进行内存分配的时候 如果进程创建时大小是固定的 比较容易 但进程的数据段 会出现增长
为了方便则可以分配额外的内存 交换出去的时候只交换实际上使用的内存的内容
空闲内存管理
2种方式跟踪内存使用情况
- 位图 几个字或几千个字节为分配单元
- 空闲链表 空间区: 开始地址: 长度
按照地址顺序在链表中存放进程和空闲区时 可以使用几种算法来分配内存
以存储管理器知道要为进程分配多大内存为前提
- 首次适配算法
除非空闲区和要分配的大小一样 否则分为2部分 1部分供进程 一部分供空闲区
- 下次适配算法
找到合适位置时候记录当时位置 以便下次继续搜索 但这个算法性能略低于上面的算法性能
- 最佳适配
遍历整个链表 找到能容纳进程的最小空闲区 但会产生大量无用的小空闲区
- 最差适配
总是分配最大的可用空闲区 使得新的空闲区比较大从而可以继续使用
虚拟内存
如今 需要运行的程序 大到内存无法容纳 交换技术也不是很有效的方案 以前是通过使用覆盖技术 即把程序分割为许多片段
程序运行时 管理模块立即装入并允许覆盖0 0执行完成后 通知1 但这是十分的繁琐并且容易出错的
于是就使用虚拟内存
每个程序拥有自己地址空间 空间被分割为多个块 每个块叫做页 每个页有连续的地址范围 页被映射到物理内存 部分页在内存中也可以运行 程序引用到物理内存的地址空间时 硬件执行映射 引用到不再物理内存中的地址空间时 OS负责装入缺失的部分
分页
虚拟地址为程序产生的地址 构成了虚拟地址空间
- 没有虚拟内存的计算机 系统直接将虚拟地址送到内存总线
- 有虚拟内存的计算机 先送到MMU(内存管理单元)进行映射
设置MMU 可以将16个虚拟页面映射到8个页框(物理内存对应单元) 有8个没有映射
如果MMU映射的是无映射的 则称为缺页中断 OS找一个使用较少的页框 去修改它 将之前无映射的页面读到页框 修改映射关系
页表
虚拟地址被分为虚拟页号 偏移量
页表项可以找到页框号 页框号拼接到偏移量的高位端 替换掉虚拟页号
虚拟页号作为页表索引 找到虚拟页面的页表项 页表项找到页框号
页表项的细节
- 页框号
- 在/不在位
- 保护位 允许什么样的访问
- 修改位
- 访问位
- 禁止高速缓存位
加速分页过程
分页式系统中 要考虑2个问题
- 虚拟地址到物理地址的映射必须快
- 虚拟地址空间很大 页表也会很大