存储管理
计算机体系结构和内存层次
内存层次: CPU有高速缓存, 未命中查内存, 内存没有查外存, 访问速度差别很大
内存管理目标: 抽象(逻辑地址空间), 保护(独立地址空间), 共享(访问相同内存), 虚拟化(更大的地址空间)
操作系统中采用的内存管理方式, 重定位(Relocation), 分段(Segmentation), 分页(Paging), 虚拟存储(Virtual Memory)
以上实现高度依赖硬件, 与计算机存储架构紧耦合, MMU(内存管理单元)是处理CPU存储访问请求的硬件, 多数系统采用按需页式虚拟存储
地址空间和地址生成
物理地址空间定义: 硬件支持的地址空间, 起始地址0, 直到MAXsys, 32位就是0到2的32次幂-1
多少位地址总线, 就是物理地址总线的条数
逻辑地址空间, 在CPU运行的进程看到的地址, 起始地址0,到MAXprog
地址生成时机: 编译时, 加载时, 执行时, 前两种简单但是不灵活, 第三种最灵活
连续内存分配
目标: 给进程分配一块不小于指定大小的连续物理内存区域
内存碎片: 空闲内存不能被利用, 外碎片(较小的剩余不连续内存区域), 内碎片(分配的内存区域未使用完的剩余部分)
动态分区分配: 当程序被加载执行时, 分配一个进程, 指定大小可变的分区, 分区的地址是连续的, 操作系统需要维护两个数据结构, 已分配分区和空闲分区
动态分区分配有三种策略:
- 最先匹配: 找第一个比申请大的区域, 分配给进程. 优点是简单, 在高地址有大块分区, 但有外部碎片, 分配大块时较慢
- 最佳分配: 找比申请大小大的最小的一个(即大小最接近的), 空闲分区按大小排序, 合并时复杂一些, 优点可避免大块分区被拆分, 减小外碎片大小, 但有外碎片, 释放分区较慢, 产生无法利用的小碎片
- 最差匹配: 找最大区域, 空闲按从大到小排, 合并复杂, 优点避免太多小碎片, 但释放慢, 有外碎片, 破坏了大分区
碎片整理
紧凑(Compaction): 通过调整进程占用的分区位置, 来减少分区碎片, 移动分配给进程的内存分区, 以合并外部碎片, 条件要求所有应用程序可动态重定位分区, 通常等待状态搬动, 还要考虑搬动开销
分区兑换(Swapping In/Out): 通过抢占并回收处于等待状态进程的分区, 以增大可用内存空间, 把等待进程放到对换区
非连续内存分配
有三种, 段式, 页式, 段页式
连续分配缺点: 分给程序内存必须连续, 存在内外碎片, 内存分配的动态修改困难, 内存利用率较低
非连续内存分配目标: 提高内存利用率和管理灵活性
允许一个程序使用非连续物理地址空间, 允许共享代码和数据, 支持动态加载和动态链接
段式存储管理
段地址空间: 进程的段地址空间由多个段组成, 主代码段, 子模块代码段, 公用库代码段, 堆栈段, 堆数据, 初始化数据段, 符号表等
段表示访问方式和存储数据等属性相同的一段地址空间, 对应一个连续的内存块, 若干个段组成进程的逻辑地址空间
段访问机制: 逻辑地址由二元组(s, addr)表示, s是段号, addr是段内偏移, 去查进程的段表, 找到段的起始地址和长度, 然后根据偏移, 找到数据
页式存储管理
把物理地址空间划分为大小相同的基本分配单位, 叫做页帧/帧(Frame), 大小2的n次幂, 常见大小4K
把逻辑地址空间也划分为相同大小的基本分配单位, 叫做页面/页(Page), 页和帧的大小必须是相同的
页到帧的转换通过页表完成
内存物理地址表示, 二元组(f,o), 帧号和偏移
不是所有的页都有对应的帧
页表概述
每个进程都有一个页表, 每个页面对应一个页表项, 随进程运行状态动态变化, 首地址放在页表基址寄存器(Page Table Base Register, PTBR)
页表项组成: 帧号, 标志位(存在位, 修改位, 引用位)
页式存储性能问题, 访问一个内存单元需要两次内存访问, 先查页表项再访问数据
当页表项过多, 页表可能非常大, 解决办法就是缓存(快表)和间接访问(多级页表)
快表: 缓存近期访问的页表项, 使用关联存储器实现
多级页表: 通过间接引用将页号分成k级, 建立页表树
反置页表: 为了减少页表所占用存储空间的一种做法, 让页表项和物理地址空间对应起来, 不和逻辑地址空间对应, 进程数量增加和虚拟地址空间增大都对页表占用没有影响
以上三种做法可缓解页表带来的麻烦
段页式存储管理
段式和页式的结合
段式存储分的块比较大, 每块内容是同一个段, 做存储的保护是比较方便的
页式存储分了很小的标准大小的块, 在内存利用效率比较有优势
实现: 在段式存储管理基础上, 给每个段加一个页表(段号, 页号, 页内偏移)