1. 功能
内存管理实现的功能:
- 抽象:逻辑地址空间
- 保护:独立地址空间
- 共享:访问相同内存
- 虚拟化:更大的地址空间
2. 管理方式
2.1 重定位
使用基址寄存器和界限寄存器,程序的起始物理地址装载到基址寄存器中,程序的长度装载到界限寄存器中。寻址时,地址=基址+偏移。
2.2 分段
将内存分为堆、堆栈、数据段、代码段等。
2.3 分页
- 页帧(帧、物理页面、Frame、Page Frame)
- 页面(页、逻辑页面、Page)
- 页表:页到帧的映射,逻辑地址中的页号是连续的,物理地址中的帧号是不连续的,不是所有的页都有对应的帧,每个进程都有一个页表,随进程运行状态而动态变化。
分页带来的问题:
- 内存访问性能问题:访问一个内存单元需要两次内存访问。
- 页表大小问题:页表可能非常大。
处理方法:
- 快表:缓存
- 多级页表
- 反置页表(倒排页表):实际内存中每个页帧对应一个表项,用虚拟地址进行散列
2.4 段页式
段式存储在内存保护方面有优势,页式存储在内存利用和优化转移到后备存储方面有优势。段页式是在段式存储的管理基础上,给每个段加一级页表。
这种方式通过指向相同的页表基址,容易实现进程间的内存共享。
2.5 虚拟存储
2.5.1 基本特征
- 不连续:物理内存分配非连续;虚拟地址空间使用非连续。
- 大用户空间:提供给用户的虚拟内存可大于实际的物理内存。
- 部分交换:只对部分虚拟地址空间进行调入和调出。
2.5.2 缺页异常(中断)的处理流程
- A.在内存中有空闲的物理页面时,分配一物理页帧 f,转第 E 步
- B.依据页面置换算法选择将被替换的物理页帧 f,对应逻辑页 q
- C.如 q 被修改过,则把它写回外存
- D.修改 q 的页表项中的驻留位为 0
- E.将需要访问的页 p 装入到物理页面 f
- F.修改 p 的页表驻留位为 1,物理帧号为 f
- G.重新执行产生缺页的指令
2.5.3 页面置换算法
2.5.3.1 局部页面置换算法
置换页面的选择范围仅限于当前进程占用的物理页面内。
1. 最优算法(OPT,optimal)
思路:置换在未来最长时间不访问的页面。
实现:缺页时,计算内存中每个逻辑页面的下一次访问时间,选择未来最长时间不访问的页面。
特征:
- 缺页最少,是理想情况。
- 实际系统中无法实现,无法预知每个页面在下次访问前的等待时间。
- 可作为置换算法的性能评价依据。
2. 先进先出算法(First-In First-Out,FIFO)
思路:选择在内存中驻留时间最长的页面进行置换。
实现:维护一个记录所有位于内存中的逻辑页面链表,链表元素按驻留内存的时间排序,链首最长,链尾最短。出现缺页时,选择链首页面进行置换,新页面加到链尾。
特征:
- 实现简单
- 性能较差,调出的页面可能是经常访问的
- 进程分配物理页面数增加时,缺页并不一定减少(Belady 现象):采用 FIFO 等算法时,可能出现分配的物理页面数增加,缺页次数反而升高的异常现象。原因:FIFO 算法的置换特征与进程访问内存的动态特征矛盾,被它置换出去的页面并不一定是进程近期不会访问的。
- 很少单独使用
3. 最近最少使用算法(Least Recently Used,LRU)
思路:缺页时,计算内存中每个逻辑页面的上一次访问时间,选择上一次使用到当前时间最长的页面。
实现:维护一个按最近访问时间排序的页面链表。
特征:开销比较大,每次访问要更新链表。
4. 时钟算法(Clock)
思路:仅对页面的访问情况进行大致统计。
数据结构:在页表项中增加访问位,描述页面在过去一段时间的内存访问情况,各页面组织成环形链表,指针指向最先调入的页面。
算法:访问页面时,在页表项记录页面访问情况,缺页时,从指针处开始顺序查找未被访问的页面进行置换。
实现:页面装入内存时,访问位初始化为 0,访问页面时,访问位置 1。缺页时,从指针当前位置顺序检查环形链表:访问位为 0,则置换该页;访问位为 1,则访问位置 0,并指针移动到下一个页面,直到找到可置换的页面。
特征:
是 LRU 和 FIFO 的折中。
5. 改进的 CLock 算法
思路:减少修改页的缺页处理(写入外存)开销。
算法:在页表项增加修改位,并在访问时进行相应修改。缺页时,修改页面标志位,以跳过有修改的页面。
6. 最不常用算法(Least Frequently Used,LFU)
思路:缺页时,置换访问次数最少的页面。
实现:每个页面设置一个访问计数,访问页面时,访问计数加 1 ,缺页时,置换计数最小的页面。
特征:
- 开销大。
- 开始时使用频繁,但以后不使用的页面很难置换。解决方法:计数定期右移。
LRU、FIFO 和 Clock 的比较
- LRU 和 FIFO 本质上都是先进先出的思路:LRU 依据页面的最近访问时间排序;FIFO 依据页面进入内存的时间排序。
- LRU 需要动态地调整顺序,FIFO 的页面进入时间是固定不变的。
- LRU 可退化成 FIFO:如页面进入内存后没有被访问,最近访问时间与进入内存的时间相同。
- LRU 算法性能较好,但系统开销大;FIFO 算法系统开销较小,但会发生 Belady 现象。
- Clock 算法是它们的折中,页面访问时,不动态调整页面在链表中的顺序,仅做标记,缺页时,再把它移动到链表末尾。
- 对于未被访问的页面,Clock 和 LRU 算法的表现一样好。对于被访问过的页面,Clock 算法不能记录准确访问顺序,而 LRU 算法可以。
2.5.3.2 全局页面置换算法
置换页面的选择范围是所有可换出的物理页面,为进程分配可变数目的物理页面。进程在不同阶段的内存需求是变化的,分配给进程的内存也需要在不同阶段有所变化。全局置换算法需要确定分配给进程的物理页面数。
CPU 利用率与并发进程数的关系:
- 进程数少时,提高并发进程数,可提高 CPU 利用率。
- 并发进程导致内存访问增加。
- 并发进程的内存访问会降低访存的局部性特征。
- 局部性特征的下降会导致缺页率上升和 CPU 利用率下降。
工作集:一个进程当前正在使用的逻辑页面集合,可表示为二元函数W(t,△),t 是当前的执行时刻,△ 称为工作集窗口,即一个定长的页面访问时间窗口。
常驻集:在当前时刻,进程实际驻留在内存当中的页面集合。
1. 工作集算法
换出不在工作集中的页面。
2. 缺页率算法
缺页率=缺页次数 / 内存访问次数 或 缺页平均时间间隔的倒数。
通过调整常驻集大小,使每个进程的缺页率保持在一个合理的范围内。