[toc]
更好的描述和控制程序的并发执行,操作系统的并发性和共享性(两个最基本特性)
为了使参与并发的程序(包含数据)能够独立运行,配备专门的数据结构
描述进程的基本情况和运行状态,控制和管理进程
- 程序段
- 相关数据段
- PCB
创建进程实际上是创建进程映像的 PCB 撤销进程实际上是撤销进程的 PCB
进程映像是静态的,进程是动态的
- 动态性(最基本):包含创建、活动、暂停、终止等过程,动态的产生、变化、消亡
- 并发性:多个进程实体同时存在与内存中
- 独立性:能够独立运行、独立获得资源、独立接受调度的基本单位
- 异步性:按各自独立的、不可预知的速度向前推进
- 结构性:进程实体是由程序段+数据段、进程控制块组成
- 运行态:进程正在处理机上运行
- 就绪态:进程获得除了处理机外的一切资源,一旦得到处理机便可立即运行
- 阻塞态:进程正在等待某一时间而暂停运行
- 创建态:进程正在被创建:首先申请一个空白 PCB,并向 PCB 中填写一些控制和管理进程的信息,系统为该进程分配运行时所必须的资源,然后转入就绪态
- 结束态:进程正在从系统中消失
一般把进程控制的程序段称为原语,特点是执行期间不允许中断
- 为新进程分配一个唯一的进程标识号,并申请一个空白 PCB(有限的)
- 为进程分配资源、为新进程的程序和数据分配必要的内存空间
- 初始化 PCB,包括初始化标志信息、初始化处理机状态信息和初始化处理机控制信息,设置进程的优先级
- 若进程就绪队列能够接纳新进程,将新进程插入就绪队列
- 正常结束
- 异常结束
- 外界干预
- 根据被终止进程的标识符,检索 PCB,从中读出该进程的状态
- 被终止进程处于执行状态,立即终止该进程的执行,将处理机资源分配给其他进程
- 若还有子孙进程,则终止其子孙进程
- 将资源归还给父进程或操作系统
- 将 PCB 从队列删除
进程的阻塞是进程自身的一种主动行为
- 通过标识号找到对应的 PCB
- 若该进程为运行态,则保护现场,将其状态转为阻塞态,停止运行
- 将 PCB 插入相应的时间等待队列,将处理机资源调度给其他就绪进程
- 在该事件的等待队列中找到相应进程的 PCB
- 将其从等待队列中移出,并设置状态为就绪态
- 将该 PCB 插入就绪队列,等待调度
- 保存处理机上下文,包括程序计数器和其他寄存器
- 更新 PCB 信息
- 把进程的PCB 移入相应的队列
- 选择另一个进程执行,并更新 PCB
- 更新内存管理的数据结构
- 回复处理机的上下文
- 进程描述信息
- 进程标识符
- 用户标识符
- 进程控制和管理信息
- 进程当前状态
- 进程优先级
- 资源分配清单
- 处理机相关信息
能被进程调度程序调度到 CPU 执行的程序代码段,多个进程可以运行同一个程序
可以是进程对应的程序加工的原始数据也可以是程序执行时产生的中间或最终结果
- 基于数据结构的共享
- 基于存储区的共享
- 直接通信方式:
- 间接通信方式:进程把消息发送到某个中间实体,接收进程从中间实体取得消息
采用半双全工通信,某一时刻要先写满,写进程先把缓冲区写满才让读进程读
减小程序在并发执行时付出的时空开销,提高操作系统的并发性能
- 进程中的一个实体
- 系统独立调度和分派的基本单位
- 线程自己不拥有系统资源
- 运行中间呈现间断性,也有就绪、阻塞和运行三种状态
方式 | 线程 | 进程 |
---|---|---|
调度 | 独立调度的基本单位 | 拥有资源的基本单位 |
拥有资源 | 不拥有资源 | 拥有资源的基本单位 |
并发性 | 线程之间可以并发执行 | 进程之间可以并发执行 |
系统空间 | 小 | 大 |
地址空间和其他资源 | 统一进程中的线程间共享进程的资源 | 进程之间的地址空间互相独立 |
通信 | 直接读写进程数据段 | 需要进程同步和互斥手段的辅助 |
- 线程是一个轻型实体,不拥有系统资源,每个线程对应一个唯一的标识符和线程控制块,线程控制块记录了线程执行的寄存器和栈等现场状态
- 不同的线程可以调用执行相同的程序,即同一个程序被不同的用户调用时,操作系统把他们创建成不同的线程
- 同一进程中的各个线程共享该进程所拥有的资源
- 线程是处理机的独立调度单位,多个线程可以并发执行
- 一个线程被创建后就开始它的生命周期
有关线程管理都由应用程序完成,内核意识不到线程的存在。 应用程序通过线程库设计成多线程程序
线程的管理工作由内核完成
多个用户级线程映射到一个内核级线程
优点:线程管理在用户空间进行,效率比较高 缺点:一个线程被阻塞时,整个进程都会被阻塞,多个线程不能并行运行在处理机
每个用户级线程映射到一个内核级线程
优点:并发能力强 缺点:创建线程的开销比较大,影响到应用程序的性能
n 个用户级进程映射到 m 个内核级线程,m <= n
对处理机进行分配,从就绪队列中选择一个进程并将处理机分配给它运行,实现进程并发执行
内存与辅存之间的调度
提高内存的利用率和系统吞吐量
从就绪队列选取一个进程将处理机分配给它
高级调度 | 中级调度 | 低级调度 | |
---|---|---|---|
次数 | 低 | 中等 | 高 |
- 处理中断过程
- 进程处于操作系统内核程序临界区
- 其他需要完全屏蔽中断的原子操作过程:加锁、解锁、中断现场保护、恢复等
- 发生引起调度条件且无法继续运行下去(非剥夺调度)
- 中断处理结束或自陷处理结束后(剥夺方式)
- 非剥夺调度方式(非抢占方式)
- 剥夺调度方式(抢占方式)
- CPU 利用率
- 系统吞吐量
- 周转时间
- 作业的周转时间
$周转时间=作业完成时间-作业提交时间$ - 平均周转时间
$平均周转时间=(作业 1 的周转时间+\cdots +作业 n 的周转时间)/ n $ - 带权周转时间
$代权周转时间=\frac{作业周转时间}{作业实际运行时间}$ - 平均带权周转时间
$平均带权周转时间=(作业 1 的带权周转时间+\cdots +作业 n 的带权周转时间)/n$
- 作业的周转时间
- 等待时间:进程处于等待处理机状态的时间之和
- 响应时间:用户提交请求到系统首次产生响应的时间
- 属于不可剥夺算法
- 算法简单,但是效率低
- 对长作业有利但是对短作业不利
- 有利于 CPU 繁忙型作业,不利于 IO 繁忙型作业
从就绪队列选择估计运行时间最短的进程,将处理机分配给它,直到完成或阻塞才释放
- 对长作业不利
- 不能保证紧迫性作业会被及时处理
- 作业的长短只是根据用户所提供的估计执行时间而定,不一定能做到真正的短作业优先
每次从后备队列选择优先级最高的一个或几个作业
- 非剥夺
- 剥夺式
- 静态优先级
- 动态优先级
- 交互型进程$>$非交互型进程(前台进程$>$后台进程)
- 系统进程$>$用户进程
- IO 型进程$>$计算型进程
- 等待时间相同时,要求服务时间越短,响应比越高,有利于短作业
- 要求服务时间相同时,作业响应比由等待时间决定,实现先来先服务
- 克服了饥饿状态,兼顾长作业
- 适用于分时系统
- 时间片的大小对系统性能影响很大
- 时间片的长短决定因素:系统的响应时间、就绪队列的进程数目、系统的处理能力
- 设置多个就绪队列,赋予不同的优先级,优先级逐次降低
- 优先级越高的队列中,运行的时间片越小
- 新进程进入内存之后,首先放在第一级的末尾,按照 FCFS 原则等待调度,如果能在时间片内完成,便可撤离系统,否则进入下一级队列的末尾
- 仅当第一级队列空时,才调度第二级队列中的进程运行
优势
- 终端用户:短作业优先
- 短批处理作业用户:周转时间较短
- 长批处理作业用户:不会长期 得不到处理
一次只允许一个进程使用的资源称为临界资源,对于临界资源的访问必须互斥进行,访问过程分为:
- 进入区:检查可否进入临界区
- 临界区:进程中访问临界资源的那段代码,又称为临界段
- 退出区:将正在访问临界区的标志清除
- 剩余区:代码中的其余部分
do{
entry section;//进入区
critical section;//临界区
exit section;//退出区
remainder section;//剩余区
}while(true)
也称制约关系,在某些位置协调他们的而工作次序而等待、传递信息所产生的的制约关系
也称间接制约关系,当一个进程进入临界区使用临界资源,另一个必须等待
应该遵循原则:
- 空闲让进
- 忙则等待
- 有限等待
- 让权等待
//p_0进程
while(turn!=0);
critical section;
turn = 1;
remainder section;
//P_1进程
while(turn!=0);
critical section;
turn = 0;
remainder section;
缺点:若某个进程不再进入临界区,另一个也同样无法进入(违背空闲让进),容易造成资源利用不充分
//P_i 进程
while(flag[j]);//1
flag[i]=true;//2
critiacal section;
flag[i]=false;
remainder section;
//P_j 进程
while(flag[i]);//3
flag[j]=true;//4
critiacal section;
flag[j]=false;
remainder section;
优点:不用交替进入,可连续使用 缺点:按照 1、2、3、4 的顺序执行,会同时进入临界区(违背忙则等待),问题出在检查和修改操作不能一次进行
//P_i 进程
flag[i]=true;
while(flag[j]);
critiacal section;
flag[i]=false;
remainder section;
//P_j 进程
flag[j]=true;
while(flag[i]);
critiacal section;
flag[j]=false;
remainder section;
缺点:双方互相谦让,结果谁也进不了临界区,导致饥饿现象
//P_i 进程
flag[i]=true;turn=j;
while(flag[j]&turn==j);
critical section;
flag[i]=false;
remainder section;
//P_j 进程
flag[j]=true;turn=i;
while(flag[i]&&turn==i);
critical section;
flag[j]=false;
remainder section;
通过硬件支持实现临界段问题的方法称为低级方法,或元方法
禁止一切中短发生,或称之为屏蔽中断、关中断
这条指令就是原子操作,执行时不允许中断,功能描述如下:
bool TestAndSet(bool *lock){
bool old;
old = *lock;
*lock = true;
return old;
}
设置一个共享布尔变量 lock,true 表示正在被占用,初始值为 false,实现进程互斥访问算法描述如下:
while TestAndSet(&lock);
进程的临界区代码段;
lock=false;
进程的其他代码段;
Swap(bool *a,bool *b){
bool temp;
temp = *a;
*a = *b;
*b = temp;
}
为每个临界资源设置一个共享布尔变量 lock,初始值为 false,每个进程再设置一个局部变量 key,用于与 lock 减缓信息,实现进程互斥访问算法描述如下:
key=true;
while(key!=false)
Swap(&lock,&key);
进程的临界区的代码段;
locl = false;
进程的其他代码段;
优点: 适用于任意数目的进程,简单、容易验证其准确性 缺点:等待进入临界区要耗费处理机的时间,不能让权等待
定义为一个用于表示资源数目的整数型量 S
wait(S){
while(S<=0);
S=S-1;
}
signal(S){
S=S+1;
}
未遵循“让权等待”的原则,而是处于“忙等”状态
typedef struct{
int value;
struct process *L;
}semaphore;
void wait(semaphore S){
S.value--;
if(S.value<0){
add this process to S.L;
block(S.L);
}
}
void signal(semaphore S){
S.value++;
if(S.value<=0){
remove a process P from S.L;
wakeup(P);
}
}
记录型信号量不存在忙等现象
只有当语句想执行完成之后语句 y 才可以执行:
semaphore S=0;
P1(){
...;
x;
V(S);
...
}
P2(){
...
P(S);
y;
...
}
semaphore S=1;
P1(){
...
P(S);
进程 P1 的临界区;
V(S);
...
}
P2(){
...
P(S);
进程 P2 的临界区;
V(S;
...
}
- 系统资源的竞争
- 进程推进顺序非法
- 死锁产生的必要条件
- 互斥条件
- 不剥夺条件:进程获得资源未使用完成之前,不能被强行夺走
- 请求并保持条件:进程已经保持了至少一个资源,又提出新的资源请求,而该资源已经被其他进程占有
- 循环等待条件:存在一种进程资源的循环等待链
- 死锁预防:设置限制条件,破坏产生死锁的 4 个必要条件之一
- 避免死锁:预防系统进入不安全的状态
- 死锁的检测以及解除
资源分配策略 | 各种可能模式 | 主要优点 | 主要缺点 | |
---|---|---|---|---|
死锁预防 | 保守,宁可资源闲置 | 一次请求所有资源,资源剥夺,资源按序分配 | 适用于突发式处理的进程,不必进行剥夺 | 效率低,进程初始化时间延长;剥夺次数过多;不便灵活申请新资源 |
死锁避免 | 是预防和检测的折中(在运行过程中判断是否可能死锁) | 寻找安全的允许顺序 | 不必进行剥夺 | 必须知道将来的资源需求;进程不能被长时间阻塞 |
死锁检测 | 宽松,只要允许就分配资源 | 定期检查死锁是否已经发生 | 不延长进程初始化时间,允许对死锁进行现场处理 | 通过剥夺解除死锁,造成损失 |
- 破坏互斥条件:不太可行
- 破坏不剥夺条件:用于状态易于保存和恢复的资源
- 破坏请求并保持:在运行前一次申请完所需要的全部资源,资源被严重浪费
- 破坏循环等待条件:采用顺序资源分配法,规定每个进程必须按照编号递增的顺序请求资源,限制了新类型设备的增加
- 资源剥夺法:挂起某些死锁进程,并抢占它的资源
- 撤销进程法:按照进程优先级和撤销进程代价的高低进行
- 进程回退法:让一个或多个进程回退到足以避免死锁的地步
- 内存空间的分配和回收
- 地址转换:逻辑地址转化为物理地址
- 内存空间的扩充:利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存
- 存储保护:保证各作业在各自的存储空间内运行,互不干扰
- 编译
- 编译程序将用户源代码编译成若干目标模块
- 链接
- 链接程序将编译后形成的一组目标模块以及所需的库函数链接在一起,形成一个完整的装入模块
- 装入
- 装入程序将装入模块装入内存运行
- 静态链接
- 在运行之前将各个目标模块以及所需的库函数链接成一个完整的可执行程序
- 装入时动态链接
- 再装入内存时,边装入边链接
- 运行时动态链接
- 在程序执行过程中需要该目标模块时才进行,便于修改和更新
- 绝对装入
- 编译程序产生绝对地址的目标代码
- 只适用于单道程序环境
- 可重定位装入
- 程序中的其他地址都是相对于始地址
- 根据内存的当前状态,将装入模块装入内存的适当位置
- 装入时对目标程序中的指令和数据的修改的过程称之为重定位
- 动态运行时装入(动态重定位)
- 地址转换推迟到真正需要执行时才进行
- 需要重定位寄存器的支持
- 可以将程序分配到不连续的存储区
- 程序运行之前可以只装入部分代码即可投入运行,运行期间动态申请分配内存
编译完成之后每个目标模块都从 0 号单元开始编址,称为该目标模块的相对地址(逻辑地址)
物理地址空间指内存中物理单元的集合
- 在 CPU 中设置一对上、下限寄存器,存放用户作业在主存中的上限和下限地址,访问地址时分别与其作比较,判断是否越界
- 采用重定位寄存器(基址寄存器)和界地址寄存器(限长寄存器),重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址的最大值
早期计算机主存容量小
程序运行时并非访问程序依据数据的各个部分,可以将用户空间分成一个固定区和若干覆盖区。经常活跃的部分放在固定区,其余部分按调用关系分段,首先将即将访问的段放入覆盖区,其他放在外存中,需要调用前将其调入覆盖区
- 打破了一个进程的全部信息装入主存后才能运行的限制
- 当同时运行程序的代码量大于主存时仍不能运行
- 只能更新覆盖区的段,不在覆盖区的段会常驻内存
- 换出:把处于等待状态的程序从内存移到辅存,把内存空间腾出来
- 换入:把准备好竞争 CPU 运行的程序从辅存移到内存
- 交换需要备份存储,通常是快速磁盘,必须足够大,提供对内存映像的直接访问
- 为了有效使用 CPU,要使每个进程执行的时间比交换的时间长
- 换出的进程序确保处于空闲状态
- 交换空间通常作为磁盘的一整块,独立于系统文件(使用起来很快)
- 减缓通常在许多进程运行且内存吃紧时开始启动,系统负荷降低时暂停
内存分为系统区和用户区,无需进行内存保护,因为内存中只有一道程序
- 优点:简单,无外部碎片,可以采用覆盖技术,无需额外的技术支持
- 缺点:只能用于单用户、单任务操作系统,有内部碎片,存储器利用率低
将用户分区空间划分为若干固定大小的区域,每个分区只能装入一道作业,当有空闲分区的时候,从外存的后备队列中选择适当大小的作业装入该分区
- 大小分区相等:用于一台计算机控制多个相同对象的场合,缺乏灵活性
- 分区大小不相等:划分为多个较小的分区、适量的中等分区、少量大分区
- 程序可能太大放不进任何一个分区
- 内存利用率低,存在内部碎片
在进程装入内存时,根据进程的大小动态的建立分区,使分区的大小刚好适合进程的需要
- 存在外部碎片的问题,可以通过紧凑技术解决,但需要动态重定位寄存器的支持,相对费时
- 首次适应算法:空闲分区按地址递增
- 最佳适应算法:空闲分区按容量递增
- 最坏适应算法:空闲分区按容量递减
- 邻近适应算法:从上一次查找结束的位置继续查找
作业道数 | 内部碎片 | 外部碎片 | 硬件支持 | 可用空间管理 | 解决碎片方法 | 解决空间不足 | 提高作业数 | |
---|---|---|---|---|---|---|---|---|
单道连续分配 | 1 | 有 | 无 | 界地址寄存器、越界检查机构 | 覆盖 | 交换 | ||
多道连续分配 | $\leq$N | 有 | 无 | |||||
多道可变连续分配 | 无 | 有 | 数组、链表 | 紧凑 |
允许有个程序分散装入不相邻的内存分区
主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位。 每个进程也以块为单位划分,进程在执行的时候,以块为单位逐个申请主存中的块空间
- 不会产生外部碎片
- 产生内部碎片相对较小(为最后一个不完整的块申请主存块空间才产生)
- 页面和页面大小
- 进程中的块称为页,内存中华的块称为页框,外存以同样的单位划分,称为块
- 页面大小是 2 的整数幂,大小应该适中
- 地址结构
31...12 11...0 页号 p 页内偏移量 w - 页表
- 记录页面内存中对应的物理块号,一般存放在内存中
- 页表由页表项构成,第一项为页号,第二项为物理内存中的块号
- 页表项的第二部分与地址项的第二部分共同组成物理地址
任务: 将逻辑地址转换为内存中的物理地址,借助页表实现 设置一个页表寄存器,存放页表在内存的起始地址 F 和页表长度 M 设页面大小为 L,逻辑地址 A 到物理地址 E 的 变换过程如下:
- 计算页号
$P=A/L$ ,页内偏移量$W=A%L$ - 比较页号
$P$ 和页表长度$M$ 。若$P≥M$ ,则产生越界中断,否则继续执行 - 页表中页号 P 对应的页表项地址=页表始址 F + 页号 P x 页表项长度,取出页表项内容 b,即为物理块号
- 计算 E=b x L + W,用得到的物理地址 E 访问内存
- 地址转换必须足够快,否则访存速度低
- 页表不能太大,否则内存利用率低
页表全部存放在内存中,存取数据或指令至少需要两次访问内存:
- 访问页表,确定物理地址
- 根据该地址存取数据或指令
快表(相联存储器):存放当前访问的若干页表项,加速地址变换过程:
- CPU 给出逻辑地址后,硬件进行地址转换,将页号送入高速缓存寄存器,将页号与快表中的所有页号比较
- 找到匹配的页号,直接从中取出该页对应的页框号,与页内偏移量拼接形成物理地址
- 若未找到,需要访问主存中的页表,读出页表项之后同时将其存入快表,若快表已满则按照一定算法替换
考虑了用户和程序员,满足方便编程、信息保护和共享、动态增长、动态链接等多方面需要
按照用户进程中的自然段划分逻辑空间,每段分配一段连续的地址空间
地址空间:
31 ... 16 | 15 ... 0 |
---|---|
段号 S | 段内偏移量 |
- 页式系统中,页号和页内偏移量对用户透明
- 段式系统中,段号和段内偏移量由用户显式提供,高级语言由编译程序完成
段号 | 段长 | 本段在主存中的始址 |
---|
设置段表寄存器,存放段表始址 F 和段表长度 M,逻辑地址 A 到物理地址 E 之间的地址变换过程如下:
- 从逻辑地址 A 中取出前几位为段号 S,后几位为段内偏移量 W
- 比较段号S和段表长度 M,若 S
$\geq$ M,则产生越界中断,否则继续执行 - 段表中段号 S 对应的段表项地址=段表始址 F+ 段号 S x 段表项长度,取出该段表项的前几位为段长 C,若偏移量
$\geq$ C,则产生越界中断 - 取出段表项中该段始址 b,E = b + W ,访问内存 E 的地址
作业的地址空间首先被分为若干逻辑段,每段有自己的段号,然后将段分为若干大小固定的页
逻辑地址结构:
段号 S | 页号 P | 页内偏移量 W |
---|
为了实现地址变换,每个进程建立一张段表,每个分段有一张页表
段表表项: 段号 + 页表长度 + 页表始址
页表表项:
页号 + 块号
系统中含有一个段表寄存器,指出作业的段表始址和段表长度
- 一次性
- 作业很大不能全部装入内存时,改作业无法运行
- 大量作业要求运行时,内存不足以容纳所有作业
- 驻留性
- 作业被装入内存后,一直驻留在内存中
- 时间局部性
- 空间局部性
- 多次性: 作业运行允许分成多次调入内存运行
- 对换性 允许作业在运行过程中,进行换进和换出
- 虚拟性 从逻辑上扩充内存的容量,使用户所看到的内存容量远大于实际的内存容量
- 请求分页存储管理
- 请求分段存储管理
- 请求段页式存储管理
- 一定容量的内存和外存
- 页表机制(段表机制)作为主要的数据结构
- 中断机构
- 地址变换机构
页表项:
页号 | 物理块号 | 状态位 P | 访问字段 A | 修改位 M | 外存地址 |
---|
增加的字段说明:
- 状态位 P:指示该页是否已调入内存
- 访问字段 A 记录本页在一段时间内被访问过的次数
- 修改位 M:标识该页在调入内存之后是否被修改过
- 外存地址:指出该页在外存上的地址,通常是物理块号
每当访问的页面不存在内存中时,便产生一个缺页中断,请求操作系统将所缺失的页调入内存,此时将缺页的进程阻塞
- 指令执行期间产生和处理中断信号,属于内部中断
- 一条指令执行期间可能会产生多次缺页中断
在地址变换时,先检索快表
- 若找到要访问的页,则修改页表项的访问位,利用页表项中给出的物理块号和页内地址形成物理地址
- 若未找到页表项,则去内存中查找页表,对比页表项的状态位 P,看是否已调入内存,未调入会产生缺页中断
淘汰以后永不使用的页面,或者最长时间内不被访问的页面,以便保证获得最低的缺页率
- 算法无法实现
优先淘汰最早进入内存的页面
选择最近最长时间未访问过的页面予以淘汰,为每个页面设置一个访问字段,记录页面自上次被访问所经历的时间
每帧附加一个使用位,0 表示最近未被修改和访问,1 相反
时钟置换算法会多遍扫描环形队列。
- 第一遍:优先寻找修改位和访问位都为0
- 第二遍:若第一遍未寻找到,则继续扫描,扫描过的节点置访问位为0,并寻找放低标准寻找未访问的修改过的页。
- 若找到,结束;未找到,重复1,2
再增加一个修改位
- 最近未被访问,也未被修改(u=0,m=0)
- 最近被访问,但未被修改(u=1,m=0)
- 最近未被访问,但被修改(u=0,m=1)
- 最近被访问,被修改(u=1,m=1)
算法过程:
- 从当前位置开始,对使用位不修改,选择第一个帧(u=0,m=0)用于替换
- 若1 失败,重新扫描,查找(u=0,m=1)的帧用于替换
- 若 2 失败,回到最初位置,且集合中所有帧的使用位均为 0,重复上两步
进程在准备执行时,不需要也不可能把一个进程所有页读入主存,因此操作系统决定给特定的进程分配几个页框,物理页框的集合就是这个进程的驻留集。需要考虑一下几点:
- 分配给一个进程的存储量越小,任何时候驻留主存的进程数量越多,可以提高处理机的时间利用率
- 若一个进程在主存的页数过小,页错误率依然会很高
- 若页数过多,给特定的进程分配更多的主存空间对该进程的错误率没有明显影响
- 固定分配局部置换
为每个进程分配一定数目的物理块
- 难以确定每个进程分配的物理块数目
- 可变分配全局置换
为系统每个进程分配一定数目的物理块,操作系统自身页保持一个空闲物理块队列。当某进程发生缺页,系统从空闲物理快队列中取出一个物理块分配给该进程
- 会盲目给进程增加物理块,导致并发能力下降
- 可变分配局部置换 为每个进程分配一定数量的物理块,某个进程发生缺页时允许从该进程在内存的页面选出一页换出,若进程平凡缺页,则系统再为进程分配若干物理块;若缺页率特别低,则适当减少分配给进程的物理块
- 预调页策略 采用以预测为基础的预调页策略
- 请求调页策略 进程运行中需要访问的页面不在内存而提出请求,由系统将所需页面调入内存
- 系统拥有足够的对换区空间 从对换区调入所需页面
- 系统缺少足够的对换区空间
- 不会被修改的文件:直接从文件区调入,换出时,由于未被修改而不必将它们换出
- 可能会被修改的文件:换厨师调到对换区,以后需要时再从对换区调入
- UNIX 方式
- 进程相关的文件放在文件区,未运行过的页面都从文件区调入
- 曾经运行过党又被换出的页面,下次调入从对换区调入
刚刚换出的页面马上又要换入主存,刚刚换入的页面马上又要换出主存
发生抖动的原因:某个进程频繁访问页面数目高于可用的物理页帧数目