第一章 操作系统引论
操作系统的目标:
有效性:提高系统资源利用率,提高系统吞吐量,方便性,可扩充性,开放性。
脱机技术:
数据的输入和输出都是在脱离主机的情况下进行的,如数据输入时,在外围机的控制下,将数据送到高速磁盘上,当cpu需要时,再将其读入内存。
脱机技术的优点:
1、减少了CPU的空闲时间
2、提高了I/O的速度
单道批处理系统和多道处理系统的区别:
单道处理系统其程序是一个接一个顺序执行的,而多道处理系统先将用户作业在外存上排成队列,然后一次往内存读入多个作业,同时执行。当一个阻塞,另外一个还能执行。
其好处是:
提高CPU利用率
提高了资源利用率:如I/O设备,内存等。
提高系统吞吐量:系统在单位时间内完成的总工作量。
操作系统的基本特性:
并发性:引入了进程和线程。
共享性:资源供进程和线程共享。
虚拟技术:时分复用如虚拟处理机技术、虚拟设备技术。空分复用,虚拟磁盘技术,虚拟存储器技术。
异步性:由于进程的执行先后,以怎么速度推进不可预知,所以具有异步性。
也就是说后三者是以并发为前提的。
操作系统的主要功能:
1、处理机管理功能
进程控制、进程同步、进程通信、调度。
2、存储器管理功能
内存分配、内存保护、地址映射、内存扩充。
3、设备管理功能
缓冲管理、设备分配、设备处理
4、文件管理
文件存储空间的管理、目录管理、文件的读/写管理和保护。
第二章 进程
2.1 进程的基本概念
程序执行时的特征:
顺序性
封闭性。独占资源
可再现性
前趋图:
前趋图是一个有向无循环图。
程序并发执行时的特征:
间断性
失去封闭性
失去可再现性
后两者的原因都是因为资源共享引起的。
进程的特征:
1、结构特征。为使程序能够独立运行,应该配置进程控制块PCB,而由程序段、数据段和PCB构成了进程实体。
创建进程,实际上是创建进程实体中的PCB,撤销也是这样。
2、动态性。进程由创建而产生,由调度而执行,由撤销而灭亡。
3、并发性。多个进程同时运行。
4、独立性。独立资源分配等。
5、异步性
进程的三种基本状态:
就绪状态、执行状态、阻塞状态。
引入挂起状态:
挂起由于终端用户的请求、父进程的请求产生。这样就有一些不一样的转换图。
引入创建状态和终止状态:
由于创建进程首先要创建PCB,填入相关信息,进入创建状态,系统分配资源之后,进入就绪状态。
图如下:
PCB:是操作系统中最重要的记录性数据结构,
主要信息如下:
进程标识符、处理机状态、进程调度信息、进程控制信息
其组织方式为:
链接方式、索引方式。
进程控制:
进程的操作术语原子操作,不允许被中断的。
2.2 进程控制
进程的创建:申请空白PCB,为新进程分配资源,初始化进程控制块,将新进程插入就绪队列。
进程的阻塞与唤醒:
进程的挂起与激活:
2.3 进程同步
两种形式的制约关系:
间接相互制约关系。若另一个进程占有资源,则这个这个进程只能阻塞。
直接相互制约关系。源于进程间的合作,如当缓冲区有数据才将进程唤醒。
临界资源:
如打印机、磁带机等。
生产者--消费者问题:
为使生产者进程与消费者进程能够并发进行,设置能容纳n个产品的缓冲区,当(in+1) mod n=out 时,缓冲区满,当in=out时,缓冲区为空。
这样用到一个产品计数器,为共享变量,是临界资源。
临界区:
每个进程中访问临界资源的那段代码称为临界区。
进程在进入临界区之前要对临界资源进行检查,若资源没有被访问,则设置其正在被访问的标志,这段代码称为进入区,之后进入临界区,完了之后恢复临界资源被访问的标志,这段代码称为退出区。
同步机制应遵循的规则:
空闲让进
忙则等待
有限等待,保证有限时间内能进入自己的临界区
让权等待,若不能进入临界区,应该释放处理机
信号量机制:
整形信号量:
利用整形量S来代表资源数目,利用两个原子操作wait(S)和signal(S)进行互斥处理。其代码如下:
wait(S): while S<=0 do no-op;
S:=S-1;
signal(S) : S:=S+1;
其缺点是当S<=0时,会不断测试。wait为进入临界区的判断,而signal为释放。
记录型信号量:
利用一种记录型的数据结构
value 代表资源数目
L :list of process 代表等待访问资源的进程
这样wait 和signal 操作可以描述为:
procedure wait(S)
var S: semaphore;
begin
S.value=S.value-1;
if S.value<0 then block(S.L);
end
procedure signal(S)
var S: semaphore;
begin
S.value=S.value+1;
if S.value<=0 then wakeup(S.L);
end
当资源不够时,则进行自我阻塞,插入信号量链表中。
而当释放资源后发现有进程在等待(S.value<=0),则唤醒链表中的第一个等待进程。
AND型信号量:
若一个进程的执行需要获得多个资源,那么前面的方法就会出现问题。
其思想是,将所有资源分配的操作做为原子操作,要么就全部分配,只要有一个资源无法分配就全部不分配。相当于在wait 操作汇中加上AND操作。
信号量集:
不是很明白??
信号量的应用:
利用信号量实现进程互斥:
只需要为资源设置互斥信号量mutex,初值为1,那么通过wait(mutex)以及signal(mutex)就能够实现进程互斥。先进去的wait会成功。
利用信号量实现前驱关系:
初始化为0,事件结束后利用signal信号释放,这样下一个通过wait(S) 操作必须要等前一个释放之后才能执行,这样环环相扣实现了前驱关系。
管制机制:
管程,由4部分组成:
管程名称
局部于管程内部的共享数据结构说明
对该数据结构进行操作的一组过程
对局部于管程内部的共享数据设置初始值的语句
不是很明白???
经典进程的同步问题:
生产者--消费者问题,读者--写者问题,哲学家进餐问题
生产者--消费者问题:
记录型信号量解决方式:
producer:
begin
repeat
produce an item in nextp;
...
wait(empty);
wait(mutex);
buffer(in):=nextp;
in:=(in+1) mod n;
signal(mutex);
signalfull);
until false;
end
consumer:
begin
repeat
wait(full);
wait(mutex);
nextc:=buffer(out);
out:=(out+1) mod n;
signal(mutex);
signal(empty);
consumer the item in nextc;
until false;
end
这里mutex 为实现对缓冲池的互斥利用,empty初始值为n,full为0,每生产一个,empty-1,生产完成full+1。消费类似。
AND信号量解决方式:
producer:
begin
repeat
produce an item in nextp;
...
Swait(empty,mutex);
buffer(in):=nextp;
in:=(in+1) mod n;
Ssignal(mutex,full);
until false;
end
consumer:
begin
repeat
...
Swait(full,mutex);
nextc:=buffer(out);
out:=(out+1) mod n;
Ssignal(mutex,empty);
<pre name="code" class="cpp">consumer the item in nextc;
until false;end
利用管程解决生产者--消费者问题
建立管程pc,包括两个过程put(item)以及get(item)过程。
type pc=monitor
Var in,out,count:integer;
buffer:array[0,...n-1] of item;
notfull,notempty:condition;
procedure entry put(item)
begin
if count>=n then notfull.wait;
buffer(in):=nextp;
in:=(in+1)mod n;
count:=count+1;
if notempty.queue then notempty.signal;
end
procedure entry get(item)
begin
if count<=0 then notempty.wait;
nextc:=buffer(out);
out:=(out+1)mod n;
count:=count-1;
if notfull.queue then notfull.signal;
end
//设置初始值 in:=out:=count:=0;
生产的时候用 pc.put(item);
消费的时候用 pc.get(item);
来替代前两种方法的中间部分即可。
哲学家进餐问题:
问题描述:
5个哲学家共用一张桌子,共有5个碗和5只筷子。
平时,一个哲学家进行思考,饥饿时拿左右靠近他的筷子,去吃饭。
利用AND信号量机制解决,当然也可以用记录型信号量来解决:
repeat
think;
Sswait(chopstick[(i+1) mod 5],chopstick[i]);
eat;
Ssignal(chopstick[(i+1) mod 5],chopstick[i]);
until false;
读者--写者问题
问题描述:
多个进程可以同时读一个文件,单写时不允许读/写,或读时不允许写。
利用
记录型信号量解决读者--写者问题
Var rmutex,wmutex:semaphore:=1,1;
readcount:interger:=0;
begin
parbegin
Reader:
begin
repeat
wait(rmutex);//不允许别的进程访问readcount
if readcount=0 then wait(wmutex);
readcount:=readcount+1;
signal(rmutex);
...
perform read operation;
...
wait(rmutex);
readcount:=readcount-1;
if readcount=0 then signal(wmutex);//<span style="font-family: Arial, Helvetica, sans-serif;">允许别的进程写入</span>
signal(rmutex);
until false;
end
writer:
begin
repeat
wait(wmutex);
perform write operation;
signal(wmutex);
until false;
end
parend
end
readcount 表示正在读的进程数目,由于多个进程共享,为其设置互斥信号rmutex。
只要有一个进程在读,就不允许写入。
若之前没有进程在读即readcount=0,那么就要进入写互斥wmutex,不允许别的进程做写操作。
同样读操作完成,没有其他进程在读readcount=0,那么释放写互斥wmutex,允许别的进程做写操作。
由于读操作中做了这样的限制,那再写操作中只需要确定没有其他进程在写就可以了。
2.5 进程通信
类型:
共享存储器系统、消息传递系统及管道通信系统。
共享存储器系统:
1、基于共享数据结构的通信方式。
2、基于共享存储区的通信方式。
消息传递系统:
是目前使用最广泛的进程通信机制,以消息(报文)为单位。
管道通信:
写进程向管道(共享文件)以字节流的形式发送大量数据,而读进程则从管道读数据。
管道必须具备三方面的协调能力:
互斥:只允许一对进程对管道进行读取。
同步:只有当写进程发完读进程才能被唤醒去读。
确定对方存在时才通信。
消息通信的实现方法:
直接通信方式、间接通信方式
直接通信方式:
Send(P1,message)
Receive(id,message)
直接提供对方的标识符。
间接通信方式:
利用信箱来保存消息。既可以实时通信,又可以非实时通信。
包括信箱的创建和撤销,消息的发送和接收如Send(mailbox,message)
信箱分为:
私用信箱:用户自己建立,别的进程可以发过来。
公用信箱:操作系统建立,其他进程可发可收。
共享信箱
消息传递系统实现中的若干问题:
通信链路:一般由发送进程在通信之前建立通信链路。
消息的格式:消息头和正文
进程同步方式:一般为发送进程不阻塞,接收进程阻塞。只有当消息过来了,才被唤醒。如打印机。
消息缓冲队列通信机制:
数据结构:
消息缓冲区:
sender 发送者进程标识符
size 消息长度
text 消息正文
next 指向下一个消息缓冲区的指针
PCB相关数据项:
mq 消息队列首指针
mutex 消息队列互斥信号量
sm 消息队列资源信号量
发送原语:
利用原语发送前,在自己的内存空间设置发送区a把相关消息信息填入其中。同时建立第一消息缓冲区i,将a中的消息复制到缓冲区中。再获得接收进程的内部标识符j.将i的消息挂在j.mq即目标进程的消息队列上。
接收原语:
目标进程从自己的消息队列mq中摘下第一个消息缓冲区i,将其消息复制到制定的消息接受区中。
发送原语可以描述为:
procedure send(receiver,a)
begin
getbuf(a.size,i);
i.sender:=a.sender;
i.size=a.size;
i.text=a.text;
i.next:=0;
getid(PCB set, receiver,j)//获得接收进程的内部标识符
wait(j.mutex);
insert(j.mq,i);//插入消息
signal(j.mutex);
signal(j,sm);
end
接收原语可以描述为:
procedure receive(b)
begin
j:=internal name; //内部标识符
wait(j.sm);
wait(j.mutex);
remove(j.mq,i);//移除
signal(j.mutex);
b.sender=i.sender;//复制一份
b.size=i.size;
b.text=i.text;
end
整个过程如图所示:
2.6 线程
引入进程和线程的目的:
引入进程,使多个程序能够并发执行,提高资源利用率和系统吞吐量。
引入线程,是为了减少程序并发时的时空开销,是系统具有更好的并发性。
线程具有哪些属性:
轻型实体。线程基本上不拥有系统资源,只有保证其独立运行的资源tcb
独立调度和分派的基本单位。由于线程是轻型实体,因此线程切换速度很快。
可并发执行。不同进程之间可以并发执行,同进程下不同线程也可并发执行。
共享进程资源。
从调度性、并发性、拥有资源、系统开销四个方面比较进程和线程:
调度性。把线程作为调度和分派的基本单位,进程作为资源拥有的基本单位,提高了并发性同一进程内线程切换不会引起线程切换。
并发性。不同进程可以并发执行,同进程下不同线程可以并发执行,提高系统资源利用率和吞吐量,提高系统并发性。
拥有资源。进程是资源拥有的基本单位,但线程基本上不拥有资源,只有tcb(必不可少),同时各线程共享进程资源。
系统开销。进程的创建、撤销、回收开销很大,进程切换时,需要保存和设置cpu环境。而线程的创建、撤销、切换、同步和通信开销很少,无需操作系统内核的干预。
什么是用户级线程和内核支持线程:
内核支持线程是在内核支持下运行的,无论用户线程还是系统线程,其创建、撤销等都需要依赖内核,在内核空间中实现。
用户级线程仅存在于用户空间中,其创建、撤销、切换同步通信无需内核支持。
说明内核支持线程和用户级线程的实现方法:
内核支持线程,在创建进程时,会分配任务数据区PTDA,同时分配若干tcb空间,当创建线程时,会填充tcb,当不够用时,重新分配tcb.
用户级线程是在用户空间上实现的,在中间系统上运行,如内核控制线程,用户级线程先连接到LWP(线程池),再连接到内核级线程上,实现内核和用户级线程的隔离。每个用户都需要一个线程池连接。
用户态和核心态的区别?
当我们在系统中执行一个程序时,大部分时间是运行在用户态下的(执行用户代码),在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态,比如说系统调用(申请使用操作系统提供的服务程序完成工作,如创建新进程),异常处理、外围设备的中断。
PS:切换步骤如下:
(1)从当前进程的描述符中提取其内核栈的ss0及esp0信息。
(2)使用ss0和esp0指向的内核栈将当前进程的cs,eip,eflags,ss,esp信息保存起来,这个过程也完成了由用户栈到内核栈的切换过程,同时保存了被暂停执行的程序的下一
条指令。
(3)将先前由中断向量检索得到的中断处理程序的cs,eip信息装入相应的寄存器,开始执行中断处理程序,这时就转到了内核态的程序执行了。
特权级的概念:
Intel x86架构的CPU来说一共有0~3四个特权级,0级最高,3级最低,系统硬件会对每条指令做特权级检查,执行用户代码时,程序运行于3级特权上,执行内科代码时,运行于0级特权上,而对于Unix/Linux来说,只使用了0级特权级和3级特权级。
用户栈和核心栈的区别?
来源:http://blog.csdn.net/cherrygarden/article/details/6829557
创建进程的同时创建进程控制块,以及创建进程自己的堆栈:用户栈和内核栈。其中用户栈的空间指向用户地址空间,内核栈的空间指向内核地址空间。
当进程运行在用户态时。CPU堆栈指针寄存器指向的是用户堆栈地址,使用的是用户堆栈;
当进程运行在内核态时,CPU堆栈指针寄存器指向的是内核堆栈地址,使用的是内核堆栈。
当系统因为系统调用(软中断)或硬件中断,CPU切换到特权工作模式,进程陷入内核态,进程使用的栈也要从用户栈转向内核栈。
从用户态到内核态要两步骤,首先是将用户堆栈地址保存到内核堆栈中,然后将CPU堆栈指针寄存器指向内核堆栈。
当由内核态转向用户态,步骤首先是将内核堆栈中得用户堆栈地址恢复到CPU堆栈指针寄存器中。
内核栈和用户栈区别:
(1)内核栈是系统运行在内核态的时候使用的栈,用户栈是系统运行在用户态时候使用的栈。
当进程由于中断进入内核态时,系统会把一些用户态的数据信息保存到内核栈中,当返回到用户态时,取出内核栈中得信息恢复出来,返回到程序原来执行的地方。
用户栈就是进程在用户空间时创建的栈,比如一般的函数调用,将会用到用户栈。
(2)内核栈是属于操作系统空间的一块固定区域,可以用于保存中断现场、保存操作系统子程序间相互调用的参数、返回值等。
而用户栈是属于用户进程空间的一块区域,用户保存用户进程子程序间的相互调用的参数、返回值等。
(3)每个进程都有4G虚拟地址空间(32位进程),“可以寻址”4G,根据实际内存会进行映射,用户栈使用0-3G地址空间,而用户栈使用3-4G地址空间。如果用户要直接访问内核栈部分,需要有特殊的方式。
为何要设置两个不同的栈?
共享原因:
内核的代码和数据是为所有的进程共享的,如果不为每一个进程设置对应的内核栈,那么就不能实现不同的进程执行不同的代码。
安全原因:
如果只有一个栈,那么用户就可以修改栈内容来突破内核安全保护。
内存池、进程池、线程池?
来源:http://blog.csdn.net/pi9nc/article/details/17141069
内存池:
内存池(Memory pool)可以更好的管理在应用程序中内存的使用,同时提高内存使用的效率。其思想如下:
首先是创建内存池。即预先分配足够大的内存,形成一个初步的“内存池”。在用户请求内存时,会返回内存池中一块空闲的内存,并将其标志置为已使用,当然具体细节和方法有很多。释放内存时,不是真正地调用free或是delete的过程,而是把内存放回内存池的过程。在把内存放入内存池的同时,要把标志位置为空闲。最后在应用程序结束时,要把内存池销毁。这里主要做的工作就是把内存池中的每一块内存释放。
使用内存池的好处:
(1)减少了内存碎片的产生。这个可以从创建内存池的过程中看出。我们在创建内存池时,分配的都是一块块比较整的内存块,这样可以减少内存碎片的产生。
(2)提高了内存的使用效率。这个可以从分配内存和释放内存的过程中看出。每次的分配与释放并不是去调用系统提供的函数或是操作符去操作实际的内存,而是在复用内存池中的内存。
缺点就是很有可能会造成内存的浪费,原因也很明显,开始分配了一大块内存,不是全部都用得到的。
线程池:
对于服务器程序而言,先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态。
对于不支持动态增加的线程池,如果没有等待线程,客户就必学等待,而对于能动态增加线程的线程池,则可以像线程池中新加一个线程。
优点:省下创建删除进程的时间,提高程序运行效率。由于刚开始需要创建线程池(线程池),也会造成资源的浪费。
PS:在面向对象程序编程中,对象的创建与析构都是一个较为复杂的过程,较费时间,所以为了提高程序的运行效率尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。
进程池和线程池原理应该差不多吧,更主要是用在服务器上。
对于这三个,以后要尝试写下代码。
第三章 处理机调度与死锁
调度算法
调度算法是指根据系统的资源分配策略所规定的资源分配算法。
几种调度算法
先来先服务调度算法(FCFS):利用队列来处理。
短作业优先调度算法(SJ(P)F):看哪个运行时间最短选哪个。
高优先权调度算法:非抢占式优先权算法和抢占式优先权调度算法(直接可以打断低优先级的),优先权又可分为静态优先权和动态优先权(可变)
高响应比优先调度算法:时间等待越长,优先级越高。
基于时间片的轮转调度算法:分配时间片,完了之后进程轮转运行。
死锁:指多个进程在运行中争夺资源而造成的一种僵局。
死锁产生的原因:
竞争资源
进程间推进顺序非法
产生死锁的必要条件:
互斥条件,资源一段时间内由一个进程占用。
请求和保持,保持资源的同时,又去请求新的资源。
不剥夺条件:资源未使用完前不可被剥夺。
环路等待条件:发生死锁时,必然存在进程--资源的额环形链。
处理死锁的基本方法:
预防死锁。通过设置限制条件,破坏死锁的一些必要条件,但由于太严格会降低资源利用率和系统吞吐量。
避免死锁。防止系统进入不安全状态,施加较弱的限制条件,如银行家算法。
检测和解除死锁,死锁发生时精确定位与死锁有关的进程和资源,然后撤销和挂起这些进程回收资源,重新分配。
第四章 存储器管理
4.1 存储器的层次结构
存储器的层次结构:
4.2 程序的装入与和链接
程序的装入和链接:
程序要运行,需要先创建进程,即将程序和数据装入内存。
步骤如下:
编译。将源程序编译成目标模块.obj
链接。将目标模块和所需的库函数链接在一起,形成一个完整的装入模块。
装入程序。将模块装入内存。
程序的装入:
绝对装入方式。程序中直接使用内存的绝对地址,装入到固定位置。
可重定位装入方式。将指令和数据进行修改,如将程序中的相对地址与内存起始地址相加形成绝对地址,但以后不能再改变所以称为重定位(静态重定位)。可装入任何位置。
动态运行时装入方式。利用重定位寄存器,在程序运行时才进行地址转换。
程序的链接:
静态链接,先全部链接成一个完整模块,再装入内存,以后不再拆开。
装入时的动态链接,方便对模块的修改、更新和共享。
运行时的动态链接,需要用哪些,才去链接哪些,可以节省大量的内存空间,加快装入过程。
4.3 连续分配方式
连续分配方式:
为用户程序分配一个连续的内存空间。
又分为:单一连续分配、固定分区分配、动态分区分配以及动态重定位分区分配。
动态分区分配:
1、
数据结构:空闲分区表,空闲分区链。
2、
分区分配算法:
首次适应算法(FF):从头至尾找到满足要求的空闲分区为止。缺点,留下很多小分区,且每次从头开始浪费时间。
循环首次适应算法(NF):从上一次为止开始,找到满足要求的即可。
最佳适应算法:将空间按顺序排列,把符合要求,又是最小的分配给程序。
最坏适应算法:从大到小排列,然后分割大的,查找效率很高,但没有大的空间了。
快速适应算法:按空间分类,找到合适的完全分配,缺点,算法复杂,时间有浪费。
3、分区分配操作:
内存分配:找到合适的,比较,若太小,则.全给,否则,切割重新利用。
回收内存:按照前后是否有空区来进行合并。
伙伴系统:
按照2的k次方进行分类,若2的i不够,则找2的i+1,分割,作为伙伴,剩下的作为空闲接着利用。合并时,同样要找伙伴合并。
哈希算法:
可重定位分区分配:
1、动态重定位的引入:
按照要求,程序必须装入连续的空间,因此将原来内存中的程序位置进行紧凑处理,挨在一起,见图:
将原来小分区拼接成大空分区,再装入程序。
因为原来的程序经过了移动,所以原来的程序和数据的地址必须进行修改和变换才行。
2、动态重定位的实现:
程序装入后,其相对地址是确定的,程序运行时,真正访问的是在内存中的绝对地址=相对地址+起始地址。而地址变换机构->重定位寄存器来存放程序在内存中的起始地址。
因此将程序在内存中移动后,只需修改重定位寄存器中的起始地址即可。实现动态重定位。
3、动态重定位分区匹配算法:
和动态分区分配方式比,当单块空间不够时,将空闲分区进行合并,若合适,则修改原来内存中程序数据结构(如修改重定位寄存器中起始地址),再将空闲分区按照动态分区进行分配。
对换:
将阻塞的进程换出到外存的对换区中(外存分为文件区和对换区,其中文件区采用离散分配方式,提高空间利用率,而对换区采用连续分配方式,提高进程换入换出速度),同时修改PCB信息。
而将就绪但是唤出时间最久的进程换入。
4.4 基本分页存储管理方式
作用:提高内存利用率。
离散分配方式:将进程分散的装入不相邻接的分区中,提高内存利用率。
页面与页表:
将程序的逻辑地址分页,内存分块,这样将页存入块中。
地址结构:页面中的地址结构为
页号与页内地址,通过逻辑地址与页面大小计算而来。
页表:页表存储页号和对应的物理块号。
地址变换机构:
1、基本的地址变换机构
当需要逻辑地址中的数据时,根据页号和页表始址计算出该表项在页表中的位置,进而访问块号,放入物理地址寄存器中,再将页内地址放入物理地址寄存器的块内地址段,完成地址转换,读取数据。
2、具有快表的地址变换机构
上面这种方法需要访问两次内存,第一次查找页表中块号,第二次才是取数据。
提出快表(输入寄存器),用来存储常用到的页表项(页号,块号),这样当得到页号之后,可以先看在快表中是否有页号,有的话直接找出块号,从而直接形成物理地址。速度快很多。
两级页表和多级页表:
4.5 基本分段存储管理方式
作用:为了满足程序员在编程和使用多方面的要求。
如:
方便编程。逻辑地址由
段号和段内偏移量组成。各段从0开始编号。
信息共享。段是信息的逻辑单位。
信息保护。同上
动态增长。如数据段会不断增长。
动态链接。运行时才将段调入内存并链接。
分段系统的基本原理:
分段:按照地址空间分段,如主程序段MAIN,子程序段X,数据段D以及栈段S等。
地址结构为:段号和段内地址。
段表:段表项由段长和基址组成。
地址变换机构:从逻辑地址中获得段号,与段表长度比较,若溢出则产生越界中断。
否则与段表始址结合,在段表中找到段表项,获得段长和基址,再看段内地址是否越界。
根据段内地址以及基址计算得到物理地址,从而获得数据。
同样为了加快速度,可以增设一个寄存器。
分页和分段的主要区别:
1、页是信息的物理单位,而段是信息的逻辑单位,分页为了提高内存的利用率,而段则是为了更好的满足用户的需要。
2、页的大小由系统决定,而段则由用户所编写的程序所决定。
3、分页的地址空间是一维的,而分段的地址空间是二维的,用户不仅需要给出段名,又需要给出段内地址。
信息共享:
分页共享:需要把要共享的代码(可重入)分页,然后各个进程建立页表,再去访问,很麻烦。
分段共享:只需要建立段表即可,这样根据段号,基址等就能找到代码段在内存中的位置。
可重入代码:不允许对代码进行修改,但是运行过程中数据会变,因此要把可能改变的数据拷贝到程序的局部数据区。
4.5 段页式存储管理方式
1、基本原理
将两者结合起来,先分段,再将段分页。
作业地址空间分为:段号,段内页号,页内地址。
2、地址变换过程
4.6 虚拟存储器的基本概念
定义:
应用程序运行之前,只装入少量页面或段,在运行时根据需要不断调入,并通过置换操作,使程序能在较小的内存中运行,从用户的角度看,比实际容量大的多。这就是虚拟存储器。
虚拟存储器的实现方法:
根据页和段有区别。单基本上是,页表机制、缺页中断机构、地址变换机构。
虚拟存储器的三大主要特征:
多次性。多次调入页面。
对换性。
虚拟性。
4.7 请求分页存储管理方式
建立在基本分页基础上,为了能支持虚拟存储器功能而增加了请求调页功能和置换功能。其比较方便,是目前最常用的一种实现虚拟存储器的方式。
1、页表机制
修改页表项为:
页号
物理块号
状态位P
访问字段A
修改位M
外存地址
其中,状态位P为页是否在内存,访问字段为最近一段时间内访问的次数,修改位M为该页在被调入内存之后是否修改,若是则需要重写入外存,保证外存中保留的是最新副本。
2、缺页中断机构
当要访问的页面不在内存时,产生缺页中断,要经过保护CPU环境、分析中断原因、转入缺页中断处理程序进行处理、恢复CPU环境。同时有2点特别的:
在指令执行期间产生和处理中断信号。
一条指令在执行期间可能产生多次缺页中断。
3、地址变换机构
内存分配策略和分配算法:
调页策略:
一般是请求调页策略。
确定从何处调入页面:
总的来讲是从文件区和对换区调入页面,根据不同情况有所区别。
页面调入过程:
可以参考地址变换机构的整个流程图来看。
4.8 页面置换算法
最佳置换算法(Optimal):置换未来最长时间内不被访问的页面。
先进先出(FIFO)页面置换算法:置换最先进入内存的页面。
最近最久未使用(LRU)置换算法:其实现需要借助硬件支持,寄存器或栈。
寄存器实现:
每个页面配置一个寄存器,当有访问的时候,在最高位置1,一段时间后右移1位,看谁最小,就将其置换出去。
栈实现:
要访问一个页面时,将其从栈中取出放在栈顶,这样栈底就是最近最长时间未访问的页面了。
Clock置换算法:
由于LRU需要硬件的支持,因此在现实中常使用Clock算法。
1、简单Clock置换算法
将页面链接成一个循环队列,依次循环访问,若为0直接换出,若为1则置为0先不换出,若没有找到0则循环。
2、改进型Clock置换算法
增加一个标志修改位M,这样就有4种页面,其中A=0,M=0是最近没有被访问且没有修改的页面,是最佳页面。
策略如下:
1)找第一类页面,若找到则置换退出,否则找第二类
2)此时,将遇到的1变为0,若找到则置换。否则重复步骤1,再否则,重复步骤2。
其它置换算法:最少使用,页面缓冲算法。
4.9请求分段存储管理方式
没有分页那么重要,
其中断处理过程如下:
段若不在内存中,则阻塞请求进程,若内存中有空闲区,则直接从外存中读入段,修改段表和内存空区链,唤醒进程。
若内存空间不够,则看总容量够不够,够的话则拼接后再进行操作,否则,需要置换掉一些段。
如何实现段的共享:
这里用到
共享段表,包括:
共享进程计数。统计有多少个进程分享该段。
存取控制字段。不同进程有不同的权限。
段号。
其分配过程如下:
当第一个进程请求共享段时,分配物理区,将其放入该区,修改请求进程段表以及共享段表内容,共享计数加1。当有其它进程需要调用该段时,无需分配内存。只要修改相应内容即可,共享计数加1.
回收过程:撤销进程段表以及共享段表相关内容,共享计数减1,当共享计数为0,则由系统回收共享段的物理内存。
直接存储器访问(DMA)I/O控制方式:
中断I/O比程序I/O更有效,但同样每传送一个字节就需要中断一次CPU。
DMA方式的特点:
1、数据传送的基本单位是数据块。
2、所传送的数据是从设备直接送入内存的,或者相反。
3、仅在传送完一个或多个数据块的开始和结束时,才需要CPU干预,整块数据的传送是在控制器的控制下完成的。
组成:
主机与DMA控制器的接口,DMA控制器与块设备的接口,I/O控制逻辑。
四类寄存器:
命令/状态寄存器(CR),内存地址寄存器(MAR),数据寄存器(DR),数据计数器(DC)
DMA工作过程:
1、CPU将读命令送入命令寄存器(CR),内存起始地址送入(MAR),字节数送入(DC),磁盘中的源地址送到DMA控制器的I/O控制逻辑上。
2、启动DMA控制器进行传送,CPU可以去处理其它任务。
3、读入一个字节到DR中后,再挪用一个存储器周期,将数据传送到MAR所指的内存单元中,且DC减1,MAR加1。
4、传送完成之后DMA控制器发出中断请求。
SPOOLing技术:
多道程序技术将一台物理CPU虚拟为多台逻辑CPU,从而允许多个用户共享一台主机。
而通过SPOOLing技术可将一台物理I/O设备虚拟为多台逻辑I/O设备。同样允许多个用户共享一台物理I/O设备。
什么是SPOOLing:
利用其中一道程序模拟脱机输入时的外围控制机功能,把低速I/O设备上的数据传送到高速磁盘上,再利用另外一道程序来模拟脱机输出时的功能,将数据从磁盘传送到低速输出设备上。
这样在主机的直接控制下,实现脱机输入、输出功能,此时外围操作与CPU对数据的处理同时进行,把这种在联机情况下实现的同时外围操作称为SPOOLing,或假脱机操作。
SPOOLing系统的组成:
输入井和输出井。模拟输入和输出时的磁盘设备,暂存数据用。
输入缓冲区和输出缓冲区。缓存从输入设备送来的数据,再送到输入井。
输入进程SPi和输出进程SPo。模拟脱机I/O时的外围控制机,将数据在设备和输入缓冲区,以及输入井之间传送。
共享打印机:
用户请求打印时,输出进程在输出井申请一个空闲磁盘块区,并申请一个用户请求打印表,填写用户打印要求,挂到打印队列上。
打印机空闲时,从打印队列上取一张请求表,将要打印数据从输出井送到内存缓冲区,再进行打印。
SPOOLing系统的特点:
1、提高了I/O的速度。从对I/O设备的读取,变为对输入井和输出井中数据的读取。
2、将独占设备改造为共享设备。在输入井中为进程分配了存储区和I/O请求表,这样实现多台机共享设备。
3、实现虚拟设备功能。对于每一个进程而言,都会认为自己是独占了一个设备。实现了将独占设备变换为若干台对应的逻辑设备的功能。