操作系统
基础概述
操作系统本质上是一个运行在计算机上的软件程序 ,用于管理计算机硬件和软件资源。
操作系统存在屏蔽了硬件层的复杂性。 操作系统就像是硬件使用的负责人,统筹着各种相关事项。
操作系统的内核是操作系统的核心部分,它负责系统的内存管理,硬件设备的管理,文件系统的管理以及应用程序的管理。 内核是连接应用程序和硬件的桥梁,决定着系统的性能和稳定性。
基本特征
并发、共享、虚拟、异步。
-
并发是指宏观上在一段时间内能同时运行多个程序,而并行则指同一时刻能运行多个指令。
-
共享是指系统中的资源可以被多个并发进程共同使用。分为:互斥共享和同时共享。
-
虚拟技术把一个物理实体转换为多个逻辑实体。
主要有两种虚拟技术:时分复用技术和空分复用技术。
-
多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占用处理器,每次只执行一小个时间片并快速切换。
-
虚拟内存使用了空分复用技术,它将物理内存抽象为地址空间,每个进程都有各自的地址空间。地址空间的页被映射到物理内存,地址空间的页并不需要全部在物理内存中,当使用到一个没有在物理内存的页时,执行页面置换算法,将该页置换到内存中。
-
-
异步指进程不是一次性执行完毕,而是走走停停,以不可知的速度向前推进。
基本功能
-
进程管理:进程控制、进程同步、进程通信、死锁处理、处理机调度等。
-
内存管理:内存分配、地址映射、内存保护与共享、虚拟内存等。
-
文件管理:文件存储空间的管理、目录管理、文件读写管理和保护等。
-
设备管理:完成用户的 I/O 请求,方便用户使用各种设备,并提高设备的利用率。
主要包括缓冲管理、设备分配、设备处理、虛拟设备等。
什么是用户态和内核态?
为了限制不同程序的访问能力,防止一些程序访问其它程序的内存数据,CPU划分了用户态和内核态两个权限等级。
- 用户态只能受限地访问内存,且不允许访问外围设备,没有占用CPU的能力,CPU资源可以被其它程序获取;
- 内核态可以访问内存所有数据以及外围设备,也可以进行程序的切换。
所有用户程序都运行在用户态,但有时需要进行一些内核态的操作,比如从硬盘或者键盘读数据,这时就需要进行系统调用,使用陷阱指令,CPU切换到内核态,执行相应的服务,再切换为用户态并返回系统调用的结果。
为什么要分用户态和内核态?
- 安全性:防止用户程序恶意或者不小心破坏系统/内存/硬件资源;
- 封装性:用户程序不需要实现更加底层的代码;
- 利于调度:如果多个用户程序都在等待键盘输入,这时就需要进行调度;统一交给操作系统调度更加方便。
如何从用户态切换到内核态?
- 系统调用:比如读取命令行输入。本质上还是通过中断实现
- 用户程序发生异常时:比如缺页异常
- 外围设备的中断:外围设备完成用户请求的操作之后,会向CPU发出中断信号,这时CPU会转去处理对应的中断处理程序
中断分类
进程的异常控制流:陷阱、中断、异常和信号
-
陷阱是有意造成的“异常”,是执行一条指令的结果。陷阱是同步的。陷阱的主要作用是实现系统调用。当进程执行这条指令后,会中断当前的控制流,陷入到内核态,执行相应的系统调用。内核的处理程序在执行结束后,会将结果返回给进程,同时退回到用户态。进程此时继续执行下一条指令。
-
中断由处理器外部的硬件产生,不是执行某条指令的结果,也无法预测发生时机。由于中断独立于当前执行的程序,因此中断是异步事件。中断包括 I/O 设备发出的 I/O 中断、各种定时器引起的时钟中断、调试程序中设置的断点等引起的调试中断等。
-
异常是一种错误情况,是执行当前指令的结果,可能被错误处理程序修正,也可能直接终止应用程序。异常是同步的。这里特指因为执行当前指令而产生的错误情况,比如除法异常、缺页异常等。
-
信号是一种更高层的软件形式的异常,同样会中断进程的控制流,可以由进程进行处理。一个信号代表了一个消息。信号的作用是用来通知进程发生了某种系统事件。
进程管理
进程和线程的区别?
- 拥有资源
进程是资源分配的基本单位,但是线程基本上不拥有资源,线程可以访问隶属进程的资源。
- 调度
线程是系统调度和分派的基本单位,进程是作为拥有系统资源的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。
- 系统开销
创建或撤销进程付出的开销远大于创建或撤销线程时的开销。进程拥有独立的地址空间,一个进程的崩溃不会影响其他进程;线程拥有自己的堆栈和局部变量,没有独立的地址空间,因此进程里的一个线程崩溃会导致其他线程均崩溃。
- 通信方面
线程间可以通过直接读写同一进程中的数据进行通信,但是进程之间的通信需要以进程间通信(IPC)的方式进行。
进程间通信(IPC)有哪些方式?
-
管道:半双工的通信方式(单向交替传输),且只能在有亲缘关系(父子进程或兄弟进程)的进程之间通信。
-
命名管道:FIFO,半双工的通信方式,但允许在无亲缘关系的进程间通信,它是一种文件类型;
-
消息队列:消息的链表,存放在内核中,并由消息队列标识符标识。
相比于 FIFO,消息队列具有以下优点:
- 消息队列可以独立于读写进程存在,从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;
- 避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法;
- 读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收。
-
信号 :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
-
信号量:是一个计数器,用于实现进程间的互斥与同步,控制多个进程间对共享资源的访问;
-
共享内存:映射一段能被其他进程访问的内存,这段内存由一个进程创建,但多个进程都可以访问,共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
需要使用信号量用来同步对共享存储的访问。
- 套接字(Socket):可用于不同机器间的进程通信。
进程同步
管程将共享变量以及对这些共享变量的操作封装起来,形成一个具有一定接口的功能模块,这样只能通过管程提供的某个过程才能访问管程中的资源。进程只能互斥地使用管程,使用完之后必须释放管程并唤醒入口等待队列中的进程。
同步与互斥的概念
- 同步:多个进程因为合作而使得进程的执行有一定的先后顺序。比如某个进程需要另一个进程提供的消息,获得消息之前进入阻塞态;
- 互斥:多个进程在同一时刻只有一个进程能进入临界区
并发、并行、异步的区别
-
并发:在一个时间段中同时有多个程序在运行,但其实任一时刻,只有一个程序在CPU上运行,宏观上的并发是通过不断的切换实现的;
-
并行(和串行相比):在多CPU系统中,多个程序无论宏观还是微观上都是同时执行的
-
异步(和同步相比):同步是顺序执行,异步是在等待某个资源的时候继续做自己的事
进程有哪几种状态?
- 就绪状态:进程已获得除处理机以外的所需资源,等待分配处理机资源
- 运行状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数
- 阻塞状态: 进程等待某种条件,在条件满足之前无法执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DltgOd60-1646465922242)(E:\Typora\imgs\image-20220222164151591.png)]
进程调度策略有哪些?
- 批处理系统
批处理系统没有太多的用户操作,在该系统中,调度算法目标是保证吞吐量和周转时间(从提交到终止的时间)。
- 先来先服务(FCFS)
非抢占式的调度算法,按照请求的顺序进行调度。
有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长。
- 短作业优先(SJF)
非抢占式的调度算法,按估计运行时间最短的顺序进行调度。
长作业有可能会饿死,处于一直等待短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度。
- 最短剩余时间优先(SRTN)
最短作业优先的抢占式版本,按剩余运行时间的顺序进行调度。 当一个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较。如果新的进程需要的时间更少,则挂起当前进程,运行新的进程。否则新的进程等待。
- 最高响应比优先(HRRN)
响应比 = 1 + 等待时间/处理时间
。
同时考虑了等待时间的长短和估计需要的执行时间长短,很好的平衡了长短进程。非抢占,吞吐量高,开销可能较大,提供好的响应时间,无饥饿问题。
- 交互式系统
交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。
- 时间片轮转
将所有就绪进程按 FCFS 的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。
时间片轮转算法的效率和时间片的大小有很大关系:
① 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。
② 如果时间片过长,那么实时性就不能得到保证。
- 优先级调度
为每个进程分配一个优先级,按优先级进行调度。
为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。
- 多级反馈队列
设置多个就绪队列1、2、3…,优先级递减,时间片递增。只有等到优先级更高的队列为空时才会调度当前队列中的进程。如果进程用完了当前队列的时间片还未执行完,则会被移到下一队列。
抢占式(时间片用完时),开销可能较大,对IO型进程有利,可能会出现饥饿问题。
- 实时系统
实时系统要求一个请求在一个确定时间内得到响应。
分为硬实时和软实时,前者必须满足绝对的截止时间,后者可以容忍一定的超时。
什么是僵尸进程?
当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。僵尸进程是一个已经死亡的进程,但是并没有真正被销毁。它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程表中保留一个位置,记载该进程的进程ID、终止状态以及资源利用信息(CPU时间,内存使用量等等)供父进程收集,除此之外,僵尸进程不再占有任何内存空间。这个僵尸进程可能会一直留在系统中直到系统重启。
危害:占用进程号,而系统所能使用的进程号是有限的;占用内存。
以下情况不会产生僵尸进程:
- 该进程的父进程先结束了。每个进程结束的时候,系统都会扫描是否存在子进程,如果有则用Init进程接管,成为该进程的父进程,并且会调用wait等待其结束。
- 父进程调用wait或者
waitpid
等待子进程结束(需要每隔一段时间查询子进程是否结束)。 - 子进程结束时,系统会产生
SIGCHLD
(signal-child)信号,可以注册一个信号处理函数,在该函数中调用waitpid
,等待所有结束的子进程(注意:一般都需要循环调用waitpid
,因为在信号处理函数开始执行之前,可能已经有多个子进程结束了,而信号处理函数只执行一次,所以要循环调用将所有结束的子进程回收); - 也可以用
signal(SIGCLD, SIG_IGN)
(signal-ignore)通知内核,表示忽略SIGCHLD
信号,那么子进程结束后,内核会进行回收。
什么是孤儿进程?
一个父进程已经结束了,但是它的子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程会被Init(进程ID为1)接管,当这些孤儿进程结束时由Init完成状态收集工作。
线程同步有哪些方式?
为什么需要线程同步:线程有时候会和其他线程共享一些资源,比如内存、数据库等。当多个线程同时读写同一份共享资源的时候,可能会发生冲突。因此需要线程的同步,多个线程按顺序访问资源。
- 互斥量
Mutex
:互斥量是内核对象,只有拥有互斥对象的线程才有访问互斥资源的权限。因为互斥对象只有一个,所以可以保证互斥资源不会被多个线程同时访问;当前拥有互斥对象的线程处理完任务后必须将互斥对象交出,以便其他线程访问该资源; - 信号量
Semaphore
:信号量是内核对象,它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。信号量对象保存了最大资源计数和当前可用资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就减1,只要当前可用资源计数大于0,就可以发出信号量信号,如果为0,则将线程放入一个队列中等待。线程处理完共享资源后,应在离开的同时通过ReleaseSemaphore
函数将当前可用资源数加1。如果信号量的取值只能为0或1,那么信号量就成为了互斥量; - 事件
Event
:允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。事件分为手动重置事件和自动重置事件。手动重置事件被设置为激发状态后,会唤醒所有等待的线程,而且一直保持为激发状态,直到程序重新把它设置为未激发状态。自动重置事件被设置为激发状态后,会唤醒一个等待中的线程,然后自动恢复为未激发状态。 - 临界区
Critical Section
:任意时刻只允许一个线程对临界资源进行访问。拥有临界区对象的线程可以访问该临界资源,其它试图访问该资源的线程将被挂起,直到临界区对象被释放。
互斥量和临界区有什么区别?
互斥量是可以命名的,可以用于不同进程之间的同步;而临界区只能用于同一进程中线程的同步。创建互斥量需要的资源更多,因此临界区的优势是速度快,节省资源。
什么是协程?
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
协程多与线程进行比较?
- 一个线程可以拥有多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
- 线程进程都是同步机制,而协程则是异步
- 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
I/O 模型
什么是文件描述符?
文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。
内核通过文件描述符来访问文件。文件描述符指向一个文件。
有哪些常见的IO模型?
- 同步阻塞IO(Blocking IO):用户线程发起IO读/写操作之后,线程阻塞,直到可以开始处理数据;对CPU资源的利用率不够;
- 同步非阻塞IO(Non-blocking IO):发起IO请求之后可以立即返回,如果没有就绪的数据,需要不断地发起IO请求直到数据就绪;不断重复请求消耗了大量的CPU资源;
- IO多路复用
- 异步IO(Asynchronous IO):用户线程发出IO请求之后,继续执行,由内核进行数据的读取并放在用户指定的缓冲区内,在IO完成之后通知用户线程直接使用。
区别:
- I/O 同步和异步的区别在于:将数据从内核复制到用户空间时,用户进程是否会阻塞(需要用户进程来完成)。
- I/O 阻塞和非阻塞的区别在于:进程发起系统调用后,是会被挂起直到收到数据后在返回、还是立即返回成功或错误。
什么是IO多路复用?怎么实现?
IO多路复用(IO Multiplexing)是指单个进程/线程就可以同时处理多个IO请求。
实现原理:用户将想要监视的文件描述符(File Descriptor)添加到select/poll/epoll
函数中,由内核监视,函数阻塞。一旦有文件描述符就绪(读就绪或写就绪),或者超时(设置timeout),函数就会返回,然后该进程可以进行相应的读/写操作。
什么是水平触发?什么是边缘触发?
- 水平触发(LT,Level Trigger)模式下,只要一个文件描述符就绪,就会触发通知,如果用户程序没有一次性把数据读写完,下次还会通知;
- 边缘触发(ET,Edge Trigger)模式下,当描述符从未就绪变为就绪时通知一次,之后不会再通知,直到再次从未就绪变为就绪(缓冲区从不可读/写变为可读/写)。
- 区别:边缘触发效率更高,减少了被重复触发的次数,函数不会返回大量用户程序可能不需要的文件描述符。
为什么边缘触发一定要用非阻塞IO?
避免由于一个描述符的阻塞读/阻塞写操作让处理其它描述符的任务出现饥饿状态。
select/poll/epoll三者的区别?
-
select
:将文件描述符放入一个集合中,调用select时,将这个集合从用户空间拷贝到内核空间(缺点1:每次都要复制,开销大),由内核根据就绪状态修改该集合的内容。(缺点2)集合大小有限制,32位机默认是1024(64位:2048);采用水平触发机制。select函数返回后,需要通过遍历这个集合,找到就绪的文件描述符(缺点3:轮询的方式效率较低),当文件描述符的数量增加时,效率会线性下降; -
poll
:和select几乎没有区别,区别在于文件描述符的存储方式不同,poll采用链表的方式存储,没有最大存储数量的限制; -
epoll
:通过内核和用户空间共享内存,避免了不断复制的问题;支持的同时连接数上限很高(1G左右的内存支持10W左右的连接数);文件描述符就绪时,采用回调机制,避免了轮询(回调函数将就绪的描述符添加到一个链表中,执行epoll_wait时,返回这个链表);支持水平触发和边缘触发,采用边缘触发机制时,只有活跃的描述符才会触发回调函数。
总结,区别主要在于:
select
:调用开销大(需要复制集合);集合大小有限制;需要遍历整个集合找到就绪的描述符,只支持水平触发。poll
:poll 采用链表的方式存储文件描述符,没有最大存储数量的限制,其他方面和 select 没有区别epoll
:调用开销小(不需要复制);集合大小无限制;采用回调机制,不需要遍历整个集合,支持水平触发和边缘触发。
什么时候使用select/poll,什么时候使用epoll?
当连接数较多并且有很多的不活跃连接时,epoll的效率比其它两者高很多;
当连接数较少并且都十分活跃的情况下,由于epoll需要很多回调,因此性能可能低于其它两者。
死锁
在多个并发进程中,每个进程持有某种资源而又等待其它进程释放它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁(deadlock)。
死锁必要条件
- 互斥:一个资源一次只能被一个进程使用。
- 占有并等待:一个进程至少占有一个资源,并在等待另一个被其它进程占用的资源。
- 不可抢占:已经分配给一个进程的资源不能被强制性抢占,只能由进程完成任务之后自愿释放。
- 循环等待:若干进程之间形成一种头尾相接的环形等待资源关系,该环路中的每个进程都在等待下一个进程所占有的资源。
死锁有哪些处理方法?
- 鸵鸟策略
直接忽略死锁。因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。
- 死锁预防
基本思想是破坏形成死锁的四个必要条件:
-
破坏互斥条件:允许某些资源同时被多个进程访问。但是有些资源本身并不具有这种属性,因此这种方案实用性有限;
-
破坏占有并等待条件:
- 实行资源预先分配策略(当一个进程开始运行 之前,必须一次性向系统申请它所需要的全部资源,否则不运行);
- 或者只允许进程在没有占用资源的时候才能申请资源(申请资源前先释放占有的资源);
- 缺点:很多时候无法预知一个进程所需的全部资源;同时,会降低资源利用率,降低系统的并发性;
-
破坏非抢占条件:允许进程强行抢占被其它进程占有的资源。会降低系统性能;
-
破坏循环等待条件:对所有资源统一编号,所有进程对资源的请求必须按照序号递增的顺序提出,即只有占有了编号较小的资源才能申请编号较大的资源。这样避免了占有大号资源的进程去申请小号资源。
-
死锁避免
动态地检测资源分配状态,以确保系统处于安全状态,只有处于安全状态时才会进行资源的分配。所谓安全状态是指:即使所有进程突然请求需要的所有资源,也能存在某种对进程的资源分配顺序,使得每一个进程运行完毕。
银行家算法
- 死锁检测
如何检测死锁:检测有向图是否存在环;或者使用类似死锁避免的检测算法。
死锁解除的方法:
- 利用抢占:挂起某些进程,并抢占它的资源。但应防止某些进程被长时间挂起而处于饥饿状态;
- 利用回滚:让某些进程回退到足以解除死锁的地步,进程回退时自愿释放资源。要求系统保持进程的历史信息,设置还原点;
- 利用杀死进程:强制杀死某些进程直到死锁解除为止,可以按照优先级进行。
内存管理
什么是虚拟内存?
虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。
每个程序都拥有自己的地址空间,这个地址空间被分成大小相等的页,这些页被映射到物理内存;但不需要所有的页都在物理内存中。当程序引用到不在物理内存中的页时,会发生缺页中断,由操作系统将缺失的部分装入物理内存,并重新执行失败的指令。
虚拟内存使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
局部性原理
局部性原理是虚拟内存技术的基础,正是因为程序运行具有局部性原理,才可以只装入部分程序到内存就开始运行。
表现在以下两个方面:
- 时间局部性:最近被访问的页在不久的将来还会被访问;产生时间局部性的典型原因:程序中存在着大量的循环操作。
- 空间局部性:内存中被访问的页周围的页也很可能被访问。因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式簇聚存储的。
虚拟内存技术实际上就是建立了 “内存一外存”的两级存储器的结构,利用局部性原理实现髙速缓存。
虚拟内存的实现方式:
-
请求分页存储管理:请求分页存储管理系统中,在作业开始运行之前,仅装入当前要执行的部分段即可运行。假如在作业运行的过程中发现要访问的页面不在内存,则由处理器通知操作系统按照对应的页面置换算法将相应的页面调入到主存,同时操作系统也可以将暂时不用的页面置换到外存中。
-
请求分段存储管理:请求分段储存管理方式就如同请求分页储存管理方式一样,在作业开始运行之前,仅装入当前要执行的部分段即可运行;在执行过程中,可使用请求调入中断动态装入要访问但又不在内存的程序段;当内存空间已满,而又需要装入新的段时,根据置换功能适当调出某个段,以便腾出空间而装入新的段。
-
请求段页式存储管理:程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。
不管是上面那种实现方式,我们一般都需要:
- 一定容量的内存和外存:在载入程序的时候,只需要将程序的一部分装入内存,而将其他部分留在外存,然后程序就可以执行了;
- 缺页中断:如果需执行的指令或访问的数据尚未在内存(称为缺页或缺段),则由处理器通知操作系统将相应的页面或段调入到内存,然后继续执行程序;
- 虚拟地址空间 :逻辑地址到物理地址的变换。
快表和多级页表
在分页内存管理中,很重要的两点是:
- 虚拟地址到物理地址的转换要快。
- 解决虚拟地址空间大,页表也会很大的问题。
快表
为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。作为页表的 Cache,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存。有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。
使用快表之后的地址转换流程是这样的:
- 根据虚拟地址中的页号查快表;
- 如果该页在快表中,直接从快表中读取相应的物理地址;
- 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
- 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。
多级页表
引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景。
有哪些页面置换算法?
页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。
- 最佳页面置换算法(OPT):置换以后不需要或者最远的将来才需要的页面,是一种理论上的算法,是最优策略;
- 先进先出(FIFO):置换在内存中驻留时间最长的页面。缺点:有可能将那些经常被访问的页面也被换出,从而使缺页率升高;为了避免这一问题,使用第二次机会算法。
- 第二次机会算法(SCR):按FIFO选择某一页面,若其访问位为0,立刻置换;若其访问位为1,给第二次机会,并将访问位清0,并把该页面放到链表的尾端。
- 时钟算法(Clock):SCR中需要将页面在链表中移动(第二次机会的时候要将这个页面从链表头移到链表尾),时钟算法使用环形链表,再使用一个指针指向最老的页面,避免了移动页面的开销;
- 最近未使用算法(NRU):当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1。检查访问位R、修改位M,优先置换R=M=0,其次是(R=0, M=1);
- 最近最久未使用算法(LRU):置换出未使用时间最长的一页;实现方式:维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。
- 最少使用算法(LFU):置换出访问次数最少的页面
分页和分段有什么区别?
- 共同点:
- 分页机制和分段机制都是为了提高内存利用率,减少内存碎片。
- 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。
- 区别:
- 目的不同:分页的目的是管理内存,用于虚拟内存以获得更大的地址空间;分段的目的是满足用户的需要,使程序和数据可以被划分为逻辑上独立的地址空间;
- 大小不同:段的大小不固定,由其所完成的功能决定;页的大小固定,由系统决定;
- 地址空间维度不同:分段是二维地址空间(段号+段内偏移),分页是一维地址空间(每个进程一个页表/多级页表,通过一个逻辑地址就能找到对应的物理地址);
- 分段便于信息的保护和共享;分页的共享收到限制;
- 碎片:分段没有内碎片,但会产生外碎片;分页没有外碎片,但会产生内碎片(一个页填不满)