《现代操作系统》03章 存储管理(四)

0 前文

《现代操作系统》03章 存储管理(一)
《现代操作系统》03章 存储管理(二)
《现代操作系统》03章 存储管理(三)

5 分页系统中的设计问题

5.1 局部分配策略与全局分配策略

主要问题

怎样在相互竞争的可运行进程之间分配内存

局部置换算法(局部分配):缺页中断发生时仅在本进程内使用置换算法

分配固定大小内存 一种是平均分配页框并留有一些页框在公用池,发生缺页中断时使用这些页框;另一种是根据进程大小按比例分配页框,同时规定一个最小页框数保证小进程的运行。
工作集监测法 工作集大小由“老化位”指出,此方法不能防止颠簸,因为老化位更新速度不及工作集

全局置换算法(全局分配):缺页中断发生时对所有页框使用置换算法

根据PFF分配 PFF(page fault frequency)即缺页中断率,一般而言PFF都会随分配页框数的增加而减少(如下图所示),监测每个进程的PFF,当发生缺页中断时,根据进程PFF控制进程的PFF保持在A.B之间,超过A表示内存不足,低于B表示内存相对过剩
请添加图片描述
PFF计算方法:这里提供三种算法。1、每秒缺页中断发生次数 2、过去数秒的缺页中断次数做连续平均 3、(当前一秒的缺页中断次数+连续平均值)/2

各算法应用方式

算法 全局算法 局部算法
FIFO
LRU及近似算法
工作集 ×
工作集时钟 ×

5.2 负载控制

只要进程总工作集大小超过内存实际大小就可能发生颠簸,这时一些进程需要更多的内存、而没有可以减少内存的进程,这时可以认为内存过载了,需要将一些进程交换到磁盘以避免颠簸的发生,随后一些进程被周期性交换到磁盘,一些进程被周期性调入内存以维持负载平衡。交换时还需要考虑进程性质(IO密集型、CPU密集型),以充分利用CPU资源。

5.3 页面大小

小页面:内存浪费少、页表大查找费时,硬盘交换费时(机械硬盘)
大页面:造成大量内存碎片,浪费内存空间,页表小查找快、相同大小的交换更省时(机械硬盘)

仅就内存浪费和页表大小的资源消耗假设:

进程平均大小s字节
页面大小p字节
没个页表项需要e字节
则页表空间大小=se/p字节
内存碎片在最后一页浪费的内存为p/2
开 销 = s e / p + p / 2 开销=se/p+p/2 =se/p+p/2
求导求极值点
− s e / p 2 + 0.5 = 0 则 p = 2 s e -se/p^2+0.5=0则 p=\sqrt{2se} se/p2+0.5=0p=2se

若s=1MB、e=8则p=4KB,商用计算机页面大小一般在512字节到64KB间

5.4 分离的指令空间和数据空间

大多数计算机仅有一个地址空间,既存放程序也存放数据,地址空间有限时,程序员对地址空间的使用出现困难。一种解决的办法是将数据空间和程序空间分离,每个空间都从0开始到某一个最大值(如2^16-1 or 2^32-1),两个空间相互独立,使用独立页表。这时需要一个链接器,他会负责两个地址空间分配的映射。

5.5 共享页面

共享页面问题一般在多用户的系统中较为常见,多个用户运行同一个进程,他们需要共享代码段以防同样的代码在内存中有多个副本,在支持分离指令、数据空间的机器中,不同的用户共享指令空间并拥有私有的数据空间。

共享页面带来一个问题,当需要进程替换或某个用户要结束一个进程时需要查询这个进程是否被共享,这需要单独的数据结构来维护。

在LInux中执行fork调用后,父进程和子进程会共享程序文本与数据,但此时数据段为只读,一旦二者中任意一方进行写操作将触发系统陷阱,系统将程序文本和数据进行复制,随后两个进程的数据读写不在影响,这种操作方式称为写时复制,大大节省软硬件资源。

5.6 共享库

在Windows中共享库称作动态链接库(DLL)首先介绍一些概念:

静态链接

链接一个程序时,要在链接器的指令中指定一个或多个目标文件,一般也会包括一些库文件。目标文件中调用了但未定义的函数(也称外部函数),链接器将会在库文件中搜索,若库文件中有则将其加载,链接完成后生成二进制文件(未被调用的库函数不会被加载)并写入磁盘。

如果每个程序都将库静态链接,那么当系统加载这些进程并运行时将会浪费大量时间和内存空间,这就引入了共享库。

共享库

当一个程序与共享库链接时,链接器不会加载被调用的库函数,而是加载一小段能够在运行时绑定被调用函数的存根历程(stub routine 可以认为是一个引导指针),当共享库函数被第一次调用时系统将其加载,没有被调用的库函数不会被加载到内存。共享库的另外一个优点是当库文件更新后,调用库函数的程序不需要重新编译。当然编译共享库时要注意不要出现绝对地址指令,即位置无关代码,因为每个进程在自己的程序中对于共享库的起始地址是不相同的。

5.7 内存映射文件

共享库可以被认为是内存映射文件的特例,内存映射文件不再局限于库,而是将文件也进行共享,这样可以实现高速的进程间通信。

5.8 清除策略

多数分页系统中存在一个分页守护进程,这个进程大多数时间在睡眠,定期被唤醒检查内存使用情况,如果内存中空闲页框较少时,守护进程会根据预定的页面置换算法将一些占用页框置换出来变为空闲页框,被修改过的页框会被写回磁盘,这些置换出的“空”页框将会放入空闲页框缓冲池,如果发生缺页中断的页面存在于缓冲池中可以迅速恢复。

还有一种方法是将分页守护进程与时钟置换算法结合,分页守护进程的指针走在页面置换指针之前,这样大大提高置换指针遇到干净页面的概率。

5.9 虚拟内存接口

这个技术的目的是为了让程序员控制内存映射,可以对内存空间命名实现共享内存,一个进程把一片内存区域的名称通知给另一个进程,使第二个进程可以把这片内存映射到它的虚拟地址空间里。用于实现高带宽共享、高性能消息传递系统。

分布式内存共享

该方法允许网络上的多个进程共享一个页面集合,这些页面可能(而不是必要的)作为单个的线性共享地址空间。当一个进程访问当前还没有映射进来的页面时,就会产生缺页中断,在内核空间或用户空间的缺页中断处理程序就会对拥有该页面的机器进行定位并向其发送一条信息,请求他清除该页面的映射并通过网络发送出来,当页面到达时就把他映射进来并重新开始运行引起中断的指令,第八章中将详细讨论(目前个人认为这就是HarmonyOS用到的技术)

6 有关实现的问题

6.1 与分页有关的工作

工作时间:进程创建、执行、缺页中断、终止时
工作内容

程序创建时:为进程创建页表,为页表项分配页框,在磁盘交换区中分配空间,对程序正文及数据交换区初始化(以便缺页中断发生时从这里将页面调入内存,有些系统直接将磁盘上的可执行文件进行分页以减少数据交换区空间占用并节省初始化时间),将页表信息、磁盘交换区信息存入进程表。
进程执行时:调度执行时,为新进程重置MMU,刷新TLB,新进程的页表替代原有页表。
缺页中断时:进行缺页中断时的置换算法
进程退出时:释放进程页表、页面、磁盘交换区(共享页面在最后一个共享进程退出后释放)

6.2 缺页中断的处理

流程:

中断发生-硬件陷入内核-在堆栈中保存PC-当前指令状态存入特殊的CPU寄存器
启动一个汇编代码例程保存通用寄存器和其他易失信息,以免被操作系统破坏(汇编代码将操作系统作为一个函数来调用)
操作系统读取引起缺页中断页面信息,这一信息有的在寄存器里可直接读取,有的需要操作系统检索PC,分析发生中断时的情况以判断需要的页面
检查引发缺页中断虚拟地址是否有效,检查存取保护是否一致-不一致则杀死进程-一致则判断是否有空闲页框-空闲直接分配-不空闲启动置换算法
干净页面-调用磁盘读取-挂起该进程直到磁盘IO完成,页框标位忙碌,在该进程挂起时其他进程可以继续运行-IO完成
脏页面-调用写磁盘-挂起该进程直到磁盘IO完成,页框标位忙碌,在该进程挂起时其他进程可以继续运行-IO完成-调用磁盘读取-挂起该进程直到磁盘IO完成,页框标位忙碌-IO完成
IO完成-页面标为正常-恢复缺页中断前指令状态-恢复PC-调度引发缺页中断的进程-操作系统返回调用它的汇编语言例程
汇编例程恢复寄存器和状态信息-返回用户空间继续执行
请添加图片描述

6.3 指令备份

这一小节主要讲解存储和恢复引起缺页中断的指令中的问题,当引起缺页中断的是一个多字节指令,那么麻烦就来了,因为在处理完缺页中断要恢复引起中断的指令,操作系统必须知道这条指令的起始地址,但PC指针并不对指令和操作数进行区分,并且在不同的CPU中对PC自增或自减可能在访问内存前、可能在访问内存后,而操作系统对此也是未知的。一种硬件的解决办法是增加一个寄存器,在执行一条指令前将PC的值保存到此寄存器中,在自增自减情况下,还可以设置第二个寄存器以保存增减信息。操作系统在中断完成后通过读取这些寄存器恢复指令。

6.4 锁定内存的页面

当一个进程发生缺页中断进行IO时会被挂起,此时又有另一进程发生缺页中断,如果使用了全局页面置换算法,也可能会对未完成IO的页面进行置换(磁盘IO一般通过DMA传输,置换算法并不知道哪个页面在IO),因此需要给正在进行IO的页面加把锁,页面算法会跳过对该页面的。另一种方法是在内核缓冲区中完成所有IO操作,IO完成再将数据复制到进程页面。

6.5 后备存储

在磁盘中开辟一块专用于磁盘交换的区域,该区域内没有普通的文件系统。系统启动时该区为空,在内存中以单独的项给出交换区的起始地址和大小。
静态交换区分页

每个进程启动时,在此区域为其分配一个等大的交换区块,进程结束后释放区块。交换分区以空闲块列表的形式组织(更好的算法在第10章讨论)。每个进程的交换区块起始地址保存在进程表中。
交换区块简单的初始化方式,一种是将进程先复制到交换区块,交换时从该区域装入内存;一种是先全部装入内存,交换时再写入交换区块。
有些进程在运行时会增长,如数据、堆栈,在复杂的系统中,应将程序正文、数据、堆栈分别划分交换区块。

动态交换区分页

不为每个进程固定分配区块,在需要时再分配,这样每个进程的交换区块是散布的,此时需要一张区块磁盘地址映射表,若页面没有在磁盘中映射,映射表对应的地址是一个非法值或以标志位来表示没有映射。

没有磁盘分区可用时

在正常的文件系统中事先定位一个或多个较大文件用来缓解交换区紧张(Windows使用该方法)。另一种方法是将进程在文件系统中的可执行文件作为交换区。在交换区紧张时也可将程序正文丢弃,当使用时再去文件系统的可执行文件读入(共享库也使用此种方式)。

6.6 策略和机制的分离

策略机制分离在进程线程调度时也提到过,策略由用户给出,运行机制由操作系统确定,这样存储管理以用户级进程运行。
请添加图片描述

程序启动-通知用户级页面调度程序-建立进程页面映射-分配磁盘交换区
缺页中断-陷入内核-缺页中断处理程序-找出需要的页面-通知用户级页面调度程序-向磁盘请求页面并放入自己的地址空间-IO完成-通知缺页中断处理程序-通知MMU修改映射,将需要的页面映射到发生缺页中断的进程

置换算法在内核

置换算法在缺页中断处理程序中完成,该程序将需要请求的页面和需要置换的页面及其数据告诉用户级页面调度进程。

置换算法在用户级调度程序

缺页中断处理程序将置换算法需要的信息及所需要的页面告诉用户级页面调度程序(用户级程序无法访问页表的访问位、修改位),可以通过页面映射、发送消息的方式实现消息传递。

机制与策略分离带来的一个问题就是多次的消息传递,上面讲到的这些消息传递其实并不是完备的,可想而知其复杂性以及对软硬件资源的消耗,但他的灵活性是不容否认的,在计算机处理速度不断增长的今天,这种消耗的影响将会越来越小。

X 往期文章

《现代操作系统》03章 存储管理(三)

《现代操作系统》03章 存储管理(二)

《现代操作系统》03章 存储管理(一)

《现代操作系统》02章 进程与线程(三)

今天,我是数据库的BOS(读者-写者问题)

哲学家不会吃饭了,我们快来帮帮他们(C语言、进程通信)

《现代操作系统》02章 进程与线程(二)

《现代操作系统》02章 进程与线程(一)

《现代操作系统》01章 基本概念

Python+OpenCV+imutils的简单图片处理(放缩、翻转、旋转、灰度RGB提取)

python手写K-means实现二维聚类.


如果文中有误,还请在评论区指正。这里是海小皮,我们一同进步!!!

Guess you like

Origin blog.csdn.net/weixin_42464904/article/details/120959903