现代操作系统学习笔记-存储管理

本文详细介绍了操作系统中的存储管理,包括地址空间的概念,如基址寄存器和界限寄存器,以及交换技术和空闲内存管理。进一步讨论了虚拟内存的原理,如分页系统、页表和页面置换算法,探讨了不同页面大小、分页系统设计问题及实现细节。此外,还提到了分段管理在现代操作系统中的应用。

0.无存储器抽象

  • 通常程序引用绝对物理地址
  • 在嵌入式系统和智能卡系统中,比较常见

一.地址空间

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

1.通常为每个CPU配置两个寄存器:基址寄存器与界限寄存器
  • 基址寄存器:存储程序的起始物理地址
  • 界限寄存器:存储程序的长度
2.当取址时自动将基址值加到进程发出的地址值上,检查该地址是否超过界限寄存器计算后的值
  • 每次访问内存都要加法运算和比较,而加法运算比较耗时
3.交换技术

交换技术,把一个进程完整的调入内存,使该进程运行一段时间,然后把它存回磁盘

  • 内存紧缩,交换在内存中产生很多个空闲区,通过把所有进程尽可能向下移动,有可能将小的空闲区合并成一个大块,但是这个操作非常耗时
  • 另一种方案为提前预留出一些内存空间给进程,当交换时仅将实际使用的空间交换出去
  • 也可分配一大块,上边为堆栈,下边为程序,程序上边为数据,中间空闲区域为堆,供给数据和堆栈使用
    堆栈
4.空闲内存管理

1)位图存储管理:每个分配单元对应于位图中的一位,0表示空闲,1表示占用(或相反)
这里写图片描述

  • 分配单元越小,位图越大;反之位图越小,但可能最后一块浪费较多
  • 查找指定长度的连续0串是耗时的,因为可能跨越字的边界?

2)链表存储管理:维护一个记录已分配内存和空闲内存段的链表,其中链表中的一个结点或者包含一个进程,或者是两个进程间的一个空闲区,P为进程,H为空闲区,X为终点
这里写图片描述

常用算法:

  • 首次适配:沿着链表找到一个足够大的空闲区,占用部分或全部,剩下的部分为新的空闲区
  • 下次适配:与首次相似,但需记住位置,用以下次查询,性能相对较低
  • 最佳适配:找到空闲区刚好等于或略大于所需空间的区域,性能差,碎片多
  • 最差适配:总是找到当前最大的空闲区分配,也不是最优
  • 两个链表:一个存使用中的空间,另一个存空闲区,好处是可以提高上述算法效率,但是增大了复杂度,和内存释放难度(将释放进程从进程表中删除,再插入到空闲表),小优化:利用单链表中的空闲区,第一个字是当前空闲区大小,第二个字指向下一个空闲区,第三个依旧指向下一个顺序节点,如此不需要P/H位
  • 快速适配:为常用大小的空闲区维护单独立链表,如4KB 8KB 12KB 等,21KB可以放在20KB表中,也可单独维护一个21KB

二.虚拟内存

基本思想:每个进程拥有自己的地址空间,这个空间被分割成多个块,每一块称作一页或页面,每一页连续的地址范围,并不需要全部页载入到内存中,当引用不在内存中的页时,由操作系统将缺失的页载入到内存,并重新执行失败的指令

1.分页
  • 内存管理单元MMU
    MMU
  • 虚拟地址构成了一个虚拟地址空间
  • 虚拟地址空间按照固定大小划分成称为页面的若干单元,在物理内存中对应的单元称为页框
  • 页面和页框大小通常是相等的
    映射
  • 缺页中断:当MMU注意到某页面没有映射,于是CPU陷入到操作系统,这个陷阱称为缺页中断。操作系统会找到一个很少使用页框并把它的内容存到磁盘(如果不在磁盘上),随后把需要访问的页面读到刚才回收的页框中,修改映射关系,然后重新执行引起陷阱的指令
  • MMU如何完成映射操作,以16个4KB页面为例,输入16位虚拟地址,输出15位物理地址,其中低12位为偏移量,高四位为页号,第四位标记是否映射
    MMU操作
2.页表

页表的目的是把虚拟页面映射为页框。从数学角度来说,页表是一个函数,它的参数是虚拟页号,结果是物理页框号。这个函数可以把虚拟地址中的虚拟页面域替换成页框域,从而形成物理地址。

1)页表项结构:
页表项

  • 保护位:指出一个页允许什么类型访问。最简单的形式是一位,0表示读/写,1表示只读。更先进的方法是3位,分别表示读、写、执行
  • 修改位:也称脏位,表示这个页面是否修改过,如果被修改过则必须写会磁盘,若未修改过且磁盘存在副本则直接丢弃
  • 访问位:在该页被写或读时,标记该位,当发生缺页中断时,优先选择未标记访问的页面
  • 高速缓存禁止位:禁止该页面被高速缓存。对映射到设备寄存器而不是常规寄存器非常重要,保证硬件是不断从设备中读数据而不是从缓存中

2)加速分页过程

主要考虑问题:
⑴虚拟地址到物理地址映射必须非常快
⑵如果虚拟地址空间很大,页表也会很大
现象:大多数程序总是对少量的页面进行多次的访问

  • 转换检测缓冲区(Translation Lookaside Buffer 简称TLB):MMU中的硬件,将虚拟地址直接映射到物理地址,而不必在访问页表
    TLB

  • MMU使用 TLB时进行并发匹配,若不在则选择一个表项清除,从内存中找到缺的页表覆盖

  • TLB软失效:不在TLB而在内存,只需要更新TLB
  • TLB硬失效:不在TLB也不再内存,需要磁盘I/O找到该页表,与软失效处理时间相差百万倍

3)针对大内存的页表(巨大的虚拟内存)

1.多级页表
如图,32位的虚拟地址被划分为10位的PT1域、10位PT2域和12位偏移量
多级页表

  • 引入多级页表,为了避免把全部页表一直保存在内存中

2.倒排页表:在实际内存中每一个页框有一个表项,表象记录哪一个(进程,虚拟页面)对定位于该页框

  • 为了增强从虚拟地址到物理地址,需要使用TLB
  • TLB失效时搜索方法: 用虚拟地址建立一张散列表,当前所有在内存中的具有相同散列值的虚拟页面被链接到一起
    倒排索引
3.页面置换算法

当发生缺页中断时,操作系统必须在内存中选择一个页面将其换出内存,以便为即将调入的页面腾出空间。如果页面在内存驻留期间修改过,就必须把它写会磁盘;如果没有修改过,则直接丢弃(因为磁盘上的副本和当前一致,不需要写回)

1)最优页面置换算法

每个页面都将该页面首次被访问前所需要执行的指令数目做标记,置换时选择标记最大的页面
#无法实现

2)最近未使用页面置换算法NRU

用R位和M位在一个简单的页面置换算法:当启动一个进程时,它的所有页面这两位都是0,R位定期地清零(如每次时钟中断时),当页面进行修改时M位置1,被访问时R位置1,则共有下面四类情况:
0,没有被访问,也没有被修改
1,没有被访问,被修改
2,被访问,没有修改
3,被访问,被修改
NRU算法随机的从编号最小的非空类中挑选一个页面淘汰

3)先进先出页面置换算法FIFO

操作系统维护一个所有当前在内存中的页面的链表,最新进入的页面放在表尾,最久进入的页面在表头。当发生缺页中断时从表头淘汰一个页面,并把新载入的页面加到表尾

4)第二次机会页面置换算法

基于FIFO算法,检查老页面的R位,如果R位是0,那么这个页面既老又没有使用,可以立即置换出去;如果R是1,就将R置为0,并把该页面放到链表尾端,修改装入时间像刚装入的一样,然后继续搜索。

5)时钟页面置换算法

由于第二次机会算法,经常在链表中移动页面,效率不是很高。更好的办法是:把所有的页面都保存在一个类似钟面的环形链表中,一个表指针指向最老的页面。
时钟页面置换算法

6)最近最少使用页面置换算法

LRU:在缺页中断发生时,置换未使用时间最长的页面。
硬件实现:
①硬件有一个64位计数器,每条指令执行完后自增1,每个页表需有一个能容纳这个计数器值的域。每次访问内存后,将当前计数器值保存到页面的页表项中。一旦发生缺页中断,操作系统检查所有页表项中计数器的值,找到值最小的一个页面,这个页面就是最近最少使用的页面。
②在一个有n个页框的机器中,LRU硬件可以维持一个初始值为0的nn位的矩阵。当访问到页框k时,将k行的位都置为1,k列都置为0。在任何时刻二进制数值最小的行就是最近最少使用的。
LRU硬件

软件实现:
①NFU:将每个页面与一个软件计数器相关联,计数器的初值为0。每次时钟中断时,由操作系统扫描内存中所有页面,将每个页面的R位加到计数器上。缺页中断时选择计数器值最小的页面。
②老化:基于NFU,在R位被加进来之前将计数器右移一位;其次将R位加到计数器最左端。
老化
老化算法有以下缺陷:
1.无法区分在一个时钟滴答内,那个页面被访问的先后顺序。
2.计数器位数只有有限位,当两个页面的计数器值一样时只能随机选择一个。
往往,时钟嘀嗒如果是20ms,8位一般够用

7)工作集页面置换算法

  • 请求调页:页面在需求时被调入,而不是预先装入
  • 局部性访问行为:进程运行的任意阶段,它都只访问较少的一部分页面
  • 工作集:一个进程当前正在使用的页面集合
  • 颠簸:若每执行几条指令程序就发生一次缺页中断,那么就称为这个程序发生了颠簸
  • 工作集模型:设法跟踪工作集,以确保让进程运行以前,它的工作集就已在内存中了,目的在于大大减少缺页中断率
  • 预先调页:在进程运行前预先装入工作集页面
  • 当前实际运行时间:一个进程从它开始执行到当前所使用CPU时间总数通常称为当前实际运行时间。
  • 生存时间:当前实际运行时间 减去 上次使用时间

基本思路,找出一个不在工作集中的页面并淘汰它。
假定由硬件记录R位和M位,每个时钟滴答中有一个定期的时钟中断会用软件方法清除R位,当发生缺页中断时:
扫描每个表
1. 若R位为1,把当前实际时间写进页表项的“上次使用时间”域中,继续扫描。
2.若R位为0,且生存时间大于t,则说明不在工作集中置换该页面,扫描继续进行更新剩余表项
3.若R位为0,且生存时间小于等于t,则记住生存时间最长的页面
4.若扫描结束后,R位都是0,则置换所记录生存时间最长的页面;若所有页面都是1,则随机选一个页面置换,最好为干净的。
工作集算法

8)工作集时钟页面置换算法

工作集时钟
类似于时钟算法,有一个循环链表和一个指针,每个页表项有R和M位
当发生缺页中断时:
1.从当前指针开始,判断R值时候为1,若为1,则更新上次使用时间,并将R位置为0,继续搜索
2. 若R为0,且生存时间大于t,W位为0,则置换出该页
3. 若R为0,生存时间大于t,W位为1,写回该页面,指针继续前进;为了降低磁盘阻塞,只允许最大写回n个页面
4. 若扫描一圈回到起点,则有两种可能:
4.1 调度过写操作,置换第一个写完成的页面(由于磁盘驱动,未必是第一个调度的页面)。
4.2 未调度过写操作,随机置换一个干净的页面,若没干净页面,则选当前页面写回磁盘,干净后置换

9)页面置换算法总结:

小结
化算法和工作集时钟算法比较实用

4.分页系统设计问题

1)局部分配策略与全局分配策略:

  • 局部配算法可以有效地为每个进程分配固定的内存片段,全局分配算法可以在运行进程之间动态的分配页框。全局分配策略更为适宜
  • PFF缺页中断率算法:指出了何时增加或减少分配给一个进程的页面数
    缺页中断率
    A :分配页框太少,缺页率过高
    B :分配的页框太多
    A与B之间为合理的缺页中断数

2)负载控制

  • 为了减少竞争内存的进程数,将一部分进程交换到磁盘,并释放他们所有的页面
  • 在交换时,不仅要考虑进程的大小、分页率也要考虑他的特性(如I/O密集或CPU密集)

3)页面大小

大页面:可能会有内部碎片(最后一个页面将近一半是空的)
小页面:需要更大的页表,页表的占用和内存磁盘交换时间都需要更多
最优页面大小公式 : P=2se
s: 进程平均大小
e: 每个页表项需要多少字节
P: 页面大小

4)分离指令空间和数据空间:
指令空间和数据空间

5)共享页面

  • 每个进程在它的进程表中有两个指针:一个指向I空间页表,另一个指向D空间页表
  • 两个进程共享页面时,各自有各自的页表,但都指向相同的页面(只读的)
  • 写时复制:当某进程需要对共享页表进行修改时,触发只读保护,陷入内核,复制一份该副本,且该副本可写

6)共享库(win中称为dll):

  • 任何在目标文件中被调用了但是没有被定义的函数称为未定义外部函数
  • 当一个共享库被装载和使用时,是以页面为单位装载的,因此没有被调用的函数是不会被装在到内存中的
  • 编译共享库时,需要用一个特殊的编译选项告知编译器,不要产生使用绝对地址的指令,只能使用相对地址。只是用相对偏移量的代码被称作位置无关代码

7)内存映射文件:

进程可以通过发起一个系统调用,将一个文件映射到其虚拟地址空间的一部分。

8)清除策略:

  • 分页守护进程:后台进程,大多数时候睡眠,但定期被唤醒检查内存的状态,若果空闲页框过少,分页守护进程通过预定的页面置换算法选择页面置换出内存
  • 策略之一双指针时钟:前指针搜索脏页面写回磁盘,后指针正常进行页面置换

9)虚拟内存接口:

  • 某些高级操作系统,程序员可以对内存映射进行控制,并通过非常规的方法增强程序行为。
  • 例如允许两个或多个进程共享同一部分内存
5.有关实现的细节:

1)有关分页的工作

进程创建、进程执行、缺页中断和进程终止

2)缺页中断处理

1.硬件陷入内核,在堆栈中保存程序计数器。
2.启动一个汇编例程保存通用寄存器和其他易失信息,这个例程将操作系统作为函数来调用
3.找出缺少的虚拟页面,通常硬件寄存器包含了这一信息,若没有的话,操作系统必须检索程序计数器,取出这条指令,用软件分析这条指令。
4.检查虚拟地址是否有效,并检查存取与保护是否一致,若不一致则发出信号或杀死进程。若果地址有效并且没有保护错误发生,系统检查是否还有空闲页框。如果没有则用页面置换算法淘汰一个页面。
5.若果选择的页框脏了,安排该页写回磁盘,并发生上下文切换,挂起该缺页中断的进程,让出资源直到传输结束。而该页框被标记为忙,不允许其他进程占用。
6.一旦页框干净,操作系统查找所需页面在磁盘上的地址,发起磁盘操作将其装入。同时,挂起该缺页中断进程。
7.当磁盘中断发生时,表明已装入,页表已经更新,页框也标记为正常状态。
8.恢复发生缺页中断指令以前的状态,程序计数器重新指向这条指令。
9.调度引发缺页中断进程,操作系统返回调用它的汇编语言例程。
10.该例程恢复寄存器和其他状态信息,返回用户空间继续执行,好像没发生过缺页中断一样。

3)指令备份

同通过一个隐藏的内部寄存器。在每条指令执行之前,把程序计数器的内容复制到该寄存器上。这些机器可能会有第二个寄存器,用来提供哪些寄存器已经自动增加或者自动减少,以及增减数量的信息

4)锁定内存页面

两种法法:
1.钉住:可以锁住正在做I/O操作的内存页面以保证它不会被移出内存。
2.在内核缓冲区中完成所有的I/O操作,然后再将数据复制到用户页面

5)后备存储

在磁盘上分配页面空间的最简单的算法是在磁盘上设置特殊的交换分区,甚至文件系统划分一块独立的磁盘
- 将整个进程映像复制到交换区,以便随时可将所需内容装入
- 将整个进程装入内存,并在需要时换出
后备存储

6)策略与机制分离

  • 基于Mach的分离方法
    MACH
    • 一个底层的MMU处理程序
    • 一个作为内核一部分的缺页中断处理程序
    • 一个运行在用户空间的外部页面调度程序
  • 页面置换算法的位置:外部页面调度程序或者内核中
    • 放在外部需要某种机制把R、M位信息传递给外部页面调度程序
  • 这样分离主要优势是更多的模块化代码和更好的适应性。主要缺点是多次交叉“用户-内核”边界引起的额外开销,以及系统模块间消息传递的额外开销
6.分段


  • 每个段由一个从0到最大线性地址序列构成
  • 不同段的长度可以不同,且可以在运行期间动态改变
  • 一般它不会同时包含多种不同类型的内容,故不同的段可以有不同种类的保护
    分页与分段比较
    1)纯分段实现

直接在内存中划分出不同大小的段,但是会产生外部碎片(棋盘形碎片),可以通过内存紧缩解决
纯分段实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值