操作系统

目录

什么是操作系统

(1 本质计算机软件,管理硬件和软件;2 为用户提供与系统交互的页面;3 分内核(能操作硬件的程序,管理系统的进程、内存、设备驱动程序、文件和网络系统等)和外壳(围绕内核的应用程序))
  1. 本质是运行在计算机上的软件,管理计算机硬件和软件;
  2. 为用户提供一个与系统交互的操作界面;
  3. 分内核与外壳(内核是能操作硬件的程序,外壳是围绕着内核的应用程序);
  4. 内核负责管理系统的进程、内存、设备驱动程序、文件和网络系统等,决定着系统的性能和稳定性,是连接应用程序和硬件的桥梁;

用户态和内核态

(1 用户态:进程执行用户代码时,处理器特权级最低;2 内核态:进程系统调用陷入内核代码执行时;3 执行文件操作、网络数据发送等操作必须通过 write、send 等系统调用,进程从用户态切换到内核态,执行完切换回用户态)
  1. 用户态:当进程在执行用户自己的代码时,则处于用户态,此时处理器特权级最低;
  2. 内核态:当进程执行系统调用而陷入内核代码中执行时,则处于内核态,此时处理器特权级最高;
  3. 如果要执行文件操作、网络数据发送等操作必须通过 write、send 等系统调用,进程将从用户态切换到内核态去执行内核代码来完成相应的操作,在执行完后又会切换回用户态。

什么是系统调用

(1 需要调用内核态级别的功能时,需通过系统调用的方式向操作系统提出服务请求,并由操作系统代为完成;2 系统调用(设备管理(设备启动请求释放)、文件管理(文件读写创建删除)、内存管理(内存分配回收等)、进程控制(进程创建撤销阻塞唤醒等)、进程通信))
  1. 根据进程访问资源的特点,可以把进程在系统上的运行分为两个级别:用户态和内核态;
  2. 进程基本都是运行在用户态,但如果需要调用内核态级别的功能(设备管理、文件管理、内存管理、进程控制、进程通信),就必须通过系统调用的方式向操作系统提出服务请求,并由操作系统代为完成;
  3. 系统调用的功能有如下几类(1 设备管理:完成设备的启动、请求、释放等功能;2 文件管理:完成文件的读、写、创建、删除等功能;3 内存管理:完成内存的分配、回收及获取作业占用内存区大小及地址等功能;4 进程控制:完成进程的创建、撤销、阻塞、唤醒等功能;5 进程通信:完成进程之间的消息传递等功能;)

虚拟技术

()
  1. 虚拟技术把一个物理实体转换为多个逻辑实体;
  2. 两种虚拟技术:时分复用技术和空分复用技术;
  3. 时分复用技术(多进程与多线程):多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占用处理器,每次只执行一小个时间片并快速切换;
  4. 空分复用技术(虚拟内存):1 虚拟内存使用了空分复用技术,能让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存;2 每个程序拥有自己的地址空间,这个地址空间被分割成多个页;3 这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中;4 当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令;5 虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能;

进程和线程

(1 进程:资源分配基本单位,拥有独立的资源(如I/O设备)和私有的地址空间,有生命周期和各种不同状态,多个进程可以在单CPU上并发执行 2 线程:独立调度基本单位,同一进程中的线程共享进程所拥有的内存空间和其他资源,每个线程拥有自己的堆栈、程序计数器和局部变量 3 区别:3.1 进程是资源分配基本单位,线程是独立调度基本单位;3.2 各进程互相独立,而同一进程中的线程极有可能互相影响;3.3 线程之间可以通过直接读写同一进程中的数据进行通信,但进程之间的通信需要借助操作系统)

1 进程

  1. 进程是资源分配的基本单位,是运行状态下的程序;
  2. 独立性:拥有独立的资源(如I/O设备)和私有的地址空间;
  3. 动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念,进程拥有自己的生命周期和各种不同的状态,而这些概念都是程序所不具备的;
  4. 并发性:多个进程可以在单个CPU上并发执行,且不会互相影响;

2 线程

  1. 线程是独立调度的基本单位;
  2. 一个进程在执行过程中可以产生多个线程,同一进程中的线程共享进程所拥有的内存空间和其他资源,每个线程拥有自己的堆栈、程序计数器和局部变量;

3 区别

  1. 进程是资源分配的基本单位,线程是独立调度的基本单位;
  2. 各进程互相独立,而同一进程中的线程极有可能互相影响;
  3. 线程执行开销小,但不利于资源的管理和保护,进程则相反;
  4. 线程之间可以通过直接读写同一进程中的数据进行通信,但进程之间的通信需要借助操作系统;
## 4JVM 的角度来看进程和线程之间的关系
1. 线程是进程划分成的更小的执行单位,一个进程在执行过程中可以产生多个线程;多个线程共享进程的堆和方法区,每个线程有自己的程序计数器、虚拟机栈和本地方法栈;
2. 各进程相互独立,而同一进程中的线程极有可能互相影响;
3. 线程执行开销小,但不利于资源的管理和保护,进程则相反;

上下文切换

进程上下文切换

(1 内容包含用户空间资源(虚拟内存、栈、全局变量等)与内核空间资源(内核堆栈、寄存器等),切换流程(1.1 前一个进程的上下文保存到它的PCB中 1.2 当前进程的PCB上下文加载到CPU中 1.3 跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行)并恢复当前进程)2 PCB(进程控制块,包括(进程描述信息(进程唯一标记符+用户标识符)、进程控制和管理信息(进程当前状态(运行、就绪、阻塞等)、进程优先级)、资源分配清单(内存地址空间、IO设备信息)、CPU 相关信息(CPU中各寄存器值))3 PCB队列:PCB通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列。将所有处于就绪状态的进程链在一起,称为就绪队列;把所有因等待某事件而处于阻塞状态的进程链在一起就组成各种阻塞队列。)

进程上下文切换的内容包含用户空间资源(虚拟内存、栈、全局变量等)与内核空间资源(内核堆栈、寄存器等)。

切换流程如下

  1. 前一个进程的上下文保存到它的PCB中;
  2. 当前进程的PCB上下文加载到CPU中;
  3. 跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行)并恢复当前进程。

在这里插入图片描述
PCB(进程控制块)的结构信息

PCB是进程存在的唯一标识,这意味一个进程一定会有对应的PCB,进程消失,PCB也会随之消失。

  1. 进程描述信息:1 进程唯一的标记符,类似唯一id;2 用户标识符,进程归属的用户,用户标识符主要为共享和保护服务;
  2. 进程控制和管理信息:1 进程当前状态,比如运行、就绪、阻塞等,作为处理机分配调度的依据;2 进程优先级,描述进程抢占处理机的优先级,优先级高的进程可以优先获得处理机;
  3. 资源分配清单:用于说明有关内存地址空间的状况,所打开文件的列表和所使用的输入/输出设备信息;
  4. CPU 相关信息:指CPU中各寄存器值,当进程被切换时,CPU状态信息都必须保存在相应的PCB中,以便进程重新执行时,能再从断点继续执行;

PCB组成的队列

PCB通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列。

  • 将所有处于就绪状态的进程链在一起,称为就绪队列;
  • 把所有因等待某事件而处于阻塞状态的进程链在一起就组成各种阻塞队列;

在这里插入图片描述

线程上下文切换

(1 不同进程的线程切换,等同于进程切换; 2 同一进程的线程切换,虚拟内存这些共享资源保持不动,只切换线程的私有数据、寄存器等不共享的数据;3 线程上下文切换的原因:(1)线程CPU时间片用完;(2)线程任务执行完成,CPU调度下一任务;(3)线程执行的任务遇到IO等阻塞操作,调度器挂起此任务调度下一任务;(4)多线程并发抢占锁资源,当前任务没有抢到锁资源,被调度器挂起,调度下一个任务;(5)用户代码挂起当前任务如线程执行sleep让出CPU;(6)硬件中断)
  1. 如果是不同进程的线程,切换的过程就跟进程上下文切换一样;
  2. 如果两个线程属于同一个进程,因为虚拟内存共享,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据;

在这里插入图片描述

引起线程上下文切换的原因

  1. 线程的CPU时间片用完;
  2. 线程执行的任务完成,系统的CPU正常调度下一个任务;
  3. 线程执行的任务遇到I/O等阻塞操作,调度器挂起此任务,继续调度下一个任务;
  4. 多个线程并发抢占锁资源,当前任务没有抢到锁资源,被调度器挂起,继续调度下一个任务;
  5. 用户的代码挂起当前任务,比如线程执行sleep方法,让出CPU;
  6. 硬件中断;

进程有哪几种状态?

(5种状态。1 新建状态(进程被创建) 2 就绪状态(准备运行,获得了除CPU之外等一切所需资源,一旦分配到CPU时间片即可运行) 3 运行状态(在CPU上运行) 4 阻塞状态(等待某一事件而暂停执行如等待某资源为可用或等待IO操作完成) 5 结束状态(进程从系统中消失))

5种状态。

  1. 新建状态(New):进程被创建,但未到就绪状态;
  2. 就绪状态(Ready):进程已处于准备运行状态,获得了除CPU之外的一切所需资源,一旦得到CPU分配的时间片即可运行;
  3. 运行状态(Running):进程正在CPU上运行;
  4. 阻塞状态(Waiting):进程正在等待某一事件而暂停执行如等待某资源为可用或等待IO操作完成;
  5. 结束状态(Terminated):进程正在从系统中消失,可能是进程正常结束或其他原因中断退出;

在这里插入图片描述

进程状态切换:1 只有就绪态和运行态可以相互转换,其他的都是单向转换;2 就绪状态的进程通过调度算法获得CPU时间片,转为运行状态;而运行状态的进程,在分配给它的CPU时间片用完后就会转为就绪状态,等待下一次调度;3 阻塞状态是因为IO操作或缺少非CPU时间片的资源从而由运行状态转换而来。

进程间有哪几种常见的通信方式?

(1 匿名管道:半双工通信,数据单向流动,父子进程通信;2 有名管道:本机任意两进程通信;3 信号:通知接收进程某个事件已经发生;4 消息队列:消息按照一定规则存储在队列中,队列按照“先进先出”的原则对消息进行管理。当一个进程需要向另一个进程发送消息时,它可以将消息放入一个指定队列中,而接收进程则可以从队列中取出消息进行处理; 5 信号量:是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,作为进程间以及同一进程内不同线程之间的同步手段;6 共享内存:即映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的进程间通信方式,它往往与信号量、互斥锁等配合使用来实现进程间的同步和通信; 7 套接字:往往用于不同主机间的进程通信,比如在客户端和服务器使用套接字中的相关函数来完成通信过程)

每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都是不可见的,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷贝到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

  1. 匿名管道(Pipes):1 半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用,进程的亲缘关系通常是指父子进程关系.
// 需要的头文件
#include <unistd.h>

// 通过pipe()函数来创建匿名管道
// 返回值:成功返回0,失败返回-1
// fd参数返回两个文件描述符
// fd[0]指向管道的读端,fd[1]指向管道的写端
// fd[1]的输出是fd[0]的输入。
int pipe (int fd[2]);

通过匿名管道实现进程间通信的步骤如下:

  1. 父进程创建管道,得到两个文件描述符指向管道的两端;
  2. 父进程fork出子进程,子进程也有两个文件描述符指向同⼀管道;
  3. 父进程关闭fd[0],子进程关闭fd[1],即父进程关闭管道读端,子进程关闭管道写端(因为管道只支持单向通信)。父进程可以往管道里写,子进程可以从管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信;

在这里插入图片描述

  1. 有名管道(Names Pipes):有名管道可以实现本机任意两个进程通信;
  2. 信号(Signal):用于通知接收进程某个事件已经发生;
  3. 消息队列(Message Queuing):消息按照一定规则存储在队列中,队列按照“先进先出”的原则对消息进行管理。当一个进程需要向另一个进程发送消息时,它可以将消息放入一个指定队列中,而接收进程则可以从队列中取出消息进行处理;
  4. 信号量(Semaphores):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,作为进程间以及同一进程内不同线程之间的同步手段;
  5. 共享内存(Shared memory):1 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。2 共享内存是最快的进程间通信方式,它往往与信号量、互斥锁等配合使用来实现进程间的同步和通信;
  6. 套接字(Sockets):往往用于不同主机间的进程通信,比如在客户端和服务器之间通过网络进行通信,是支持TCP/IP的网络通信的基本操作单元,使用套接字中的相关函数来完成通信过程;

线程间的同步方式有哪几种?

(1 互斥量:互斥对象机制,只有拥有互斥对象的线程才有权限访问公共资源,可以避免公共资源被多个线程同时访问,Java中的sychronized关键字和各种Lock;2 信号量:允许同一时刻多个线程访问同一资源,需要控制同一时刻访问此资源的最大线程数量;3 事件:利用通知操作的方式来实现多线程同步,Java中的Wait/Notify)
  1. 互斥量(Mutex):1 采用互斥对象机制,只有拥有互斥对象的线程才有权限访问公共资源 2 由于互斥对象只有一个,因此可以避免公共资源被多个线程同时访问 3 Java中的sychronized关键字和各种Lock都是这种机制;
  2. 信号量(Semaphore):1 允许同一时刻多个线程访问同一资源 2 但需要控制同一时刻访问此资源的最大线程数量;
  3. 事件(Event):1 利用通知操作的方式来实现多线程同步 2 比如Java中的Wait/Notify就是这种机制;

操作系统中进程的调度算法有哪些?

(1 批处理系统: 没有太多用户操作,目标保证吞吐量和较短平均周转时间。1.1 先来先服务FCFS(按请求顺序进行调度,有利于长作业不利于短作业(短作业等待时间长),平均周转时间较长)1.2 最短作业优先SJF(按估计运行时间最短进行调度,有利于短作业不利于长作业(可能饿死),平均周转时间短)1.3 抢占式最短作业优先SRTN(向最短作业优先添加抢占,如果新到达的进程运行时间比当前运行进程的剩余运行时间更短,则由新进程抢占处理机,平均周转时间最短) 2 交互式系统:大量的用户交互,目标是快速响应。2.1 时间片轮转(就绪进程按FCFS原则排成队列,每次调度时CPU时间片分配给队首进程,该进程执行一个时间片,时间片用完将该进程送往队列末尾,继续把时间片分给队首进程。时间片太小,频繁切换花费过多时间;时间片太大,实时性得不到保证) 2.2 优先级调度(为每个进程分配优先级,按优先级调度,为防止低优先级进程永远得不到调度,可随时间推移增加等待进程优先级) 2.3 多级反馈队列(一进程需执行100个时间片,如果时间片轮转调度,需交换100次。多级反馈队列为这种需要连续执行多个时间片的进程考虑,设置了多个队列,每个队列时间片大小不同,如1,2,4,8…进程第一个队列没执行完移到下一个队列,如此只需交换7次;每个队列优先权也不同,最上面的优先权最高,因此只有上一个队列没有进程在排队时,才能调度当前队列上的进程;可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合) 3 实时系统:要求一个请求在一个确定时间内得到响应,分硬实时和软实时,前者必须满足绝对的截止时间,后者可容忍一定的超时。最早截止时间优先(给截止时间最早的任务赋予最高的优先级。如果一个新任务到达,并且它的截止时间比当前正在执行的任务还要早,那么调度程序就会中断当前的任务,开始执行新任务))

不同环境的调度算法目标不同,因此需要针对不同环境来讨论。

1 批处理系统

批处理系统没有太多的用户操作,在该系统中,调度算法的目标是保证吞吐量和较短的平均周转时间。

  1. 先来先服务(FCFS):1 按照请求的顺序进行调度;2 有利于长作业,不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长,平均周转时间较长;
  2. 最短作业优先(SJF,非抢占):1 按估计运行时间最短的顺序进行调度;2 有利于短作业,平均周转时间短;3 长作业有可能会饿死,处于一直等待短作业执行完毕的状态,因为如果一直有短作业到来,长作业永远得不到调度;
  3. 抢占式最短作业优先(SRTN):1 向最短作业优先添加抢占;2 如果新到达的进程运行时间比当前运行进程的剩余运行时间更短,则由新进程抢占处理机;3 平均周转时间最短;

2 交互式系统

交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。

  1. 时间片轮转:1.1 将所有就绪进程按FCFS的原则排成一个队列,每次调度时,把CPU时间片分配给队首进程,该进程可以执行一个时间片;1.2 当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并把它送往就绪队列的末尾,同时继续把CPU时间片分配给队首的进程;1.3 时间片轮转算法的效率和时间片的大小有很大关系:如果时间片太小,会导致进程切换太频繁,在进程切换上会花费过多时间;如果时间片太大,实时性就不能得到保证;
  2. 优先级调度:2.1 为每个进程分配一个优先级,按优先级进行调度;2.2 为了防止低优先级的进程永远得不到调度,可以随着时间的推移增加等待进程的优先级;
  3. 多级反馈队列:3.1 一个进程需要执行100个时间片,如果采用时间片轮转调度算法,需要交换100次;3.2 多级反馈队列是为这种需要连续执行多个时间片的进程考虑,它设置了多个队列,每个队列时间片大小都不相同,例如1,2,4,8…。进程在第一个队列没执行完,就会被移到下一个队列。这种方式下,之前的进程只需要交换7次;3.3 每个队列优先权也不同,最上面的优先权最高,因此只有上一个队列没有进程在排队时,才能调度当前队列上的进程;3.4 可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合;

3 实时系统

  1. 实时系统要求一个请求在一个确定时间内得到响应;
  2. 分为硬实时和软实时,前者必须满足绝对的截止时间,后者可以容忍一定的超时;
  3. 最早截止时间优先(EDF):这种算法会给截止时间最早的任务赋予最高的优先级。如果一个新的任务到达,并且它的截止时间比当前正在执行的任务还要早,那么调度程序就会中断当前的任务,开始执行新的任务。

操作系统的内存管理主要是做什么

()
  1. 内存的分配与回收(malloc函数:申请内存;free函数:释放内存);
  2. 地址转换工作:将逻辑地址转换成相应的物理地址;

操作系统有哪几种内存管理机制

()
  1. 1 分连续分配管理和非连续分配管理这两种。2 连续分配管理是指为一个程序分配一个连续的内存空间,如块式管理;3 非连续分配管理方式是指为一个程序分配的内存可以是离散的或者说是不相邻的,如页式管理、段式管理、段页式管理;
  2. 块式管理:1 原始计算机系统的内存管理方式。2 将主存划分为几个固定大小的块,每个块中只包含一个进程;3 如果程序运行需要内存的话,操作系统就分配给它一块;4 如果程序运行只需要很小的内存的话,分配的这块内存很大一部分就被浪费了;5 这些在每个块中未被利用的内存称之为碎片;
  3. 页式管理:1 把主存划分为大小相等且固定的一页一页的形式,页较小,相比于块式管理划分力度更大,提高了内存利用率,减少了碎片;2 页式管理通过页表对应逻辑地址和物理地址;
  4. 段式管理

虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页,每一页再与内存进行映射。

分页地址映射是一种一维空间的映射,在编译器中动态编译程序时,并不清楚程序总共需要多少内存空间,所以分配的内存地址空间中划分的堆栈区、数据区、代码区、常量存储区等在动态增长的过程中可能会覆盖到其他的分区位置。

在这里插入图片描述
分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。

在这里插入图片描述
4. 段页式管理: 1 程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页;2 这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能(现代操作系统采用段页式);

分页机制和分段机制的共同点和区别

()

1 共同点

  1. 都是为了减少内存碎片,提高内存利用率;
  2. 页和段都是离散存储的,但每个页和每个段中的内存是连续的;

2 区别

  1. 对程序员的透明性:分页透明,但是分段需要程序员显式地划分每个段;
  2. 地址空间的维度:分页是一维地址空间,分段是二维地址空间;
  3. 大小是否可以改变:页的大小不可变,段的大小可以动态改变;
  4. 出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护;

为什么分页机制中逻辑地址空间是一维的,而分段机制中逻辑地址空间是二维的?

()
  1. 分页机制中逻辑地址的结构:页号+页内偏移量;分段机制中逻辑地址的结构:段号+段内偏移量;
  2. 假如有一段程序采用分页机制,这段程序会被编译成一大段机器指令,这些指令之间地址是连续的:

在这里插入图片描述

  1. 从图中可以看出逻辑地址空间如果采用分页机制,那么第0页的最后一个地址和第1页的第一个地址在数值上是连续的,因此分页机制的逻辑地址空间是一维的;
  2. 如果采用分段机制,那么这段程序就会被编译成多个段,比如数据段、代码段、附加段等,从图中可以看出虽然数据段、代码段的段号是连续的,但是数据段的最后一个地址和代码段的第一个地址是不连续,因此分段机制中的地址不是一维的,而是二维的;

在这里插入图片描述

页表管理机制中有两个很重要的概念:快表和多级页表,它们分别解决了页表管理中很重要的两个问题,请叙述。

  1. 在分页内存管理中,很重要的两点是:1 虚拟地址到物理地址的转换要快;2 解决虚拟地址空间大,页表也会很大的问题;
  2. 快表:1.1 为了提高虚拟地址到物理地址的转换速度,引入了快表;1.2 可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的部分或全部内容;1.3作为页表的Cache,它的作用与页表相似,但是提高了访问速率;1.4 由于采用页表做地址转换,读写内存数据时CPU要访问两次主存,有了快表,有时只要访问一次高速缓冲存储器、一次主存,这样就可加速查找并提高指令执行速度;1.5 使用快表之后的地址转换流程如下(1 根据虚拟地址中的页号查快表;2 如果该页在快表中,直接从快表中读取相应的物理地址;3 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;4 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页);
  3. 多级页表:引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。比如一级页表和二级页表,一级页表对应了二级页表(比如每个一级页表项对应1K个二级页表项),其中一级页表覆盖了整个虚拟地址空间,而二级页表可以在需要时才创建,或者先放到磁盘等需要时再调入主存。如此就极大节约了内存。具体可以参考: 多级页表如何节约内存.
  4. 总结:不管是快表还是多级页表实际上都利用了程序的局部性原理。

程序的局部性原理

  1. 主要分为时间局部性和空间局部性;
  2. 时间局部性:如果执行了程序中的某条指令,则不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问(因为程序中存在大量的循环);
  3. 空间局部性:一旦程序访问了某个存储单元,则不久之后其附近的存储单元也很有可能被访问(因为很多数据在内存中都是连续存放的,并且程序的指令也是顺序地在内存中存放的);

在这里插入图片描述

逻辑地址和物理地址

  1. 逻辑地址:逻辑地址由操作系统决定,和编程打交道的一般都是逻辑地址。比如在C语言中,指针里存储的数值就是内存里的一个逻辑地址;
  2. 物理地址:即真实物理内存中的地址,更具体一点来说就是内存地址寄存器中的地址;

CPU寻址是什么?为什么需要虚拟地址空间?

  1. CPU寻址:CPU需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。完成虚拟地址转换为物理地址任务的是CPU中一个被称为内存管理单元(Memory Management Unit, MMU)的硬件。

  2. 为什么要有虚拟地址空间?1 如果没有虚拟地址空间,程序直接访问和操作的都是物理内存。就会带来两个问题:1.1 用户程序可以访问任意内存,这样很容易破坏操作系统,造成操作系统崩溃;1.2 想要同时运行多个程序特别困难。比如想同时运行一个微信和一个QQ都不行。因为当微信在运行时给内存地址1XXX赋值后,QQ也可能同样给内存地址1XXX赋值,那么QQ对内存的赋值就会覆盖微信之前的赋值,如此就造成了微信程序的崩溃。2 而通过虚拟地址访问内存有以下优势:2.1 程序可以使用⼀系列相邻的虚拟地址来访问物理内存中不相邻的内存缓冲区;2.2 程序可以使用⼀系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将内存页保存到磁盘文件,在需要时进行数据交换;2.3 不同进程使用的虚拟地址彼此隔离,因此⼀个进程无法访问正在由另⼀进程访问的物理内存;

分页系统地址映射

  1. 内存管理单元(MMU)管理着地址空间和物理内存的转换,其中的页表(Page table)存储着页(程序地址空间)和页框(物理内存空间)的映射表;
  2. 下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位,也就是存储页面号,剩下 12 个比特位存储偏移量;
  3. 例如对于虚拟地址(0010 000000000100),前 4 位是存储页面号 2,读取表项内容为(1101)。该页在内存中,并且页框的地址为(110 000000000100);
    在这里插入图片描述

虚拟内存

  1. 虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存;
  2. 每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页;
  3. 这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中;
  4. 当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令;
  5. 虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能;

虚拟存储器

  1. 基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其他部分放在外存,就可以启动程序运行;
  2. 当访问的内容不在内存中时,由操作系统将所需要的内容调入内存,然后继续执行程序。同时,操作系统将内存中暂时不使用的内容换到外存上,从而腾出空间存放将要调入内存的内容;
  3. 这样,计算机好像为用户提供了一个比实际内存大得多的存储器——虚拟存储器;

虚拟内存技术的实现

虚拟内存技术的实现需要建立在离散分配的内存管理方式的基础上,有以下三种实现方式:

1 请求分页式存储管理

  1. 建立在分页存储管理之上,增加了请求调页和页面置换功能;
  2. 请求分页是最常用的实现虚拟存储器的方法;
  3. 在作业开始运行前,仅装入当前要执行的部分页即可运行;
  4. 如果在执行过程中发现要访问的页不在内存,则由操作系统按照对应的页面置换算法将对应的页调入内存,同时将暂时不用的页置换到外存;

2 请求分段式存储管理

  1. 建立在分段存储管理之上,增加了请求调段和分段置换功能;
  2. 在作业开始运行之前,仅装入当前要执行的部分段即可运行;
  3. 如果在执行过程中发现要访问的段不在内存,则使用请求调入中断来动态装入对应的段,同时按照分段置换算法将暂时不用的段置换到外存;

3 请求段页式存储管理
结合了段式存储管理和页式存储管理特点的存储管理方式。它将程序分为若干个逻辑段,每个段再划分为若干个大小相等的页。

请求分页存储管理与分页存储管理的不同?

  1. 请求分页存储管理建立在分页存储管理之上;
  2. 请求分页存储管理不要求将作业全部地址空间同时装入主存,而分页存储管理要求。基于这一点,请求分页存储管理可以提供虚拟内存,而分页存储管理不可以;

页面置换算法

0 背景

  1. 在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中;
  2. 此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间;
  3. 页面置换算法的主要目标是使页面置换频率最低(即缺页率最低);

1 OPT(Optimal,最佳)

  1. 被换出的页面将是最长时间内不再被访问的页面,可以保证获得最低的缺页率;
  2. 是一种理论上的算法,因为无法知道一个页面多长时间不再被访问,因此该算法无法实现,一般用来衡量其他置换算法;

2 LRU(Least Recently Used,最近最少使用)

  1. 将最近最少的页面换出;
  2. 为了实现LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头,这样就能保证链表表尾的页面是最近最少使用的;
  3. 由于每次访问都需要更新链表,因此这种方式实现的代价很高;

3 NRU(Not Recently Used,最近未使用)

  1. 每个页面都有两个状态位:R与M,当页面被访问时设置R=1,当页面被修改时设置M=1。其中R位会定时被清0;
  2. 可以将页面分成四类:1 R=0,M=0;2 R=0,M=1;3 R=1,M=0;4 R=1,M=1;
  3. 当发生缺页中断时,NRU随机从类编号最小的非空类中挑选一个页面将它换出;
  4. NRU优先换出已经被修改的脏页面(R=0,M=1),而不是被频繁访问的干净页面(R=1,M=0);

4 FIFO(First In First Out,先进先出)

  1. 选择换出的页面是最先进入的页面;
  2. 可能将那些经常被访问的页面也被换出,从而使缺页率升高;

5 第二次机会算法

  1. FIFO算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一些优化;
  2. 当页面被访问(读或写)时设置该页面的R位为1;
  3. 需要替换时,检查最老页面的R位,如果R位是0,说明这个页面既老又没有被使用,可以立刻置换掉;
  4. 如果R位是1,则将R位清0,并把该页面放到链表的尾端,修改它的装入时间就像它刚装入一样,然后继续从链表头部开始搜索;

6 时钟算法

第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,使用一个指针指向最老的页面。

在这里插入图片描述

死锁

死锁概念及本质原因

概念:多个并发进程因争夺系统资源而产生互相等待的现象;

本质原因

  1. 系统资源有限;
  2. 进程推进顺序不合理;

死锁产生的必要条件

  1. 互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束;
  2. 占有和等待:一个进程本身占有资源,同时还有一些资源未得到满足,正在等待其他进程释放这些资源;
  3. 不可抢占:已经分配给一个进程的资源不能被强制性地抢占,它只能被占有它的进程显式地释放;
  4. 循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源;

死锁的处理方法

  1. 鸵鸟策略;
  2. 死锁检测与死锁恢复(不阻止,发生时恢复);
  3. 死锁预防(运行前);
  4. 死锁避免(运行时);

1 鸵鸟策略

  1. 把头埋进沙子里,假装没发生问题,即不采取任何措施;
  2. 由于处理死锁的代价很高,因此鸵鸟策略会获得更高的性能;
  3. 当死锁不会对用户造成很大影响、或者发生死锁的概率很低时,可以采用鸵鸟策略;
  4. 大多数操作系统,包括 Unix、Linux 和 Windows,处理死锁都采用鸵鸟策略,然后手动干预(重新启动);

2 死锁检测与死锁恢复(不阻止,发生时恢复)

不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。

  1. 每种类型一个资源的死锁检测:1 每种类型一个资源的死锁检测算法通过检测有向图是否存在环来实现;2 依次从每一个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到了死锁的发生;
  2. 每种类型多个资源的死锁检测: 1 E 向量:资源总量;A 向量:资源剩余量;C 矩阵:每个进程所拥有的资源数量;R 矩阵:每个进程请求的资源数量;2 每个进程最开始时都不被标记,执行过程有可能被标记。当算法结束时,任何没有被标记的进程都是死锁进程;3 3.1寻找一个没有被标记的进程 Pi,它所请求的资源R[i]小于等于 A;3.2 如果找到了这样一个进程,那么将它拥有的资源C[i]加到 A 中,并标记该进程,同时转回上一步;3.3如果没有这样一个进程,算法终止;如果最后所有进程都被标记,则没有死锁,否则有死锁;
  3. 死锁恢复: 1 通过抢占恢复;2 通过回滚恢复;3 通过杀死进程恢复;

3 死锁预防(运行前)

在程序运行前预防死锁。

  1. 破坏互斥:例如假脱机打印机技术允许若干个进程同时输出,唯一真正请求物理打印机的进程是打印机守护进程。
  2. 破坏占有和等待:1 方法1:所有进程在开始运行前,必须一次性申请其在整个运行过程中所需要的全部资源。 优点:简单易实施且安全; 缺点:因为某项资源不满足,进程无法启动,而其他已经满足了的资源也不会得到利用,造成资源浪费,使进程经常发生饥饿现象;2 方法2:对第一种方法的改进,允许进程只获得运行初期需要的资源,便开始运行,在运行过程中逐步释放已经使用完毕的资源,再去请求新的资源。这样的话,资源的利用率会得到提高,也会减少进程的饥饿现象。
  3. 破坏不可抢占:1. 当一个已经持有了一些资源的进程在提出新的资源请求没有得到满足时,它必须释放已经保持的所有资源,待以后需要使用的时候再重新申请,这就意味着进程已占有的资源被抢占了;2. 这种方法实现比较复杂,代价也比较大。释放已经保持的资源很可能会导致进程之前的工作失效,也可能导致进程的执行被无限推迟;
  4. 破坏循环等待:给资源统一编号,进程只能按编号顺序来请求资源。当一个进程拥有编号为 i 的资源时,那么它下一次只能申请编号大于 i 的资源;

4 死锁避免(运行时)

在程序运行时避免死锁。

  1. 安全状态:如果没有死锁发生,并且即使所有进程突然请求对资源的最大需求,也依然存在某种调度次序能够使得每一个进程执行完毕,那么该状态是安全的;
  2. 单个资源的银行家算法:1 检查是否有足够的额度满足某一客户,如果有,那么这笔贷款就是能够收回的,并将此客户的贷款加入可用额度里,接着检查能够满足的另一个客户,以此类推;2 如果最终所有贷款都能被收回,那么该状态就是安全的(满足该请求),否则不安全(推迟该请求);
  3. 多个资源的银行家算法: 1 检查还需分配资源的矩阵是否存在一行小于等于可用资源的向量。如果不存在这样的行,那么系统将发生死锁,状态是不安全的;2 假若找到这样一行,标记该进程,并将其已分配资源加到可用资源的向量中;3 重复以上两步,如果最终所有进程都被标记,则状态是安全的(满足该请求),否则不安全(推迟该请求);

活锁、饥饿

活锁

任务没有被阻塞,只是由于某些条件没有被满足,导致线程一直重复尝试、失败、尝试、失败。例如,线程1和线程2都需要获取一资源,但它们同时让其他线程先获取该资源,两线程一直谦让,最后都无法获取。(活锁不断尝试,死锁一直等待)

饥饿

线程因为种种原因无法获得所需要的资源,导致一直处于无法执行的状态。以磁盘调度算法为例,如果采用“最短寻道时间优先”的策略,如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现了饥饿现象,尤其是两端的磁道请求更容易出现饥饿现象。

磁盘调度算法

  1. 读写一个磁盘块的时间影响因素有:1 旋转时间(主轴转动盘面,使得磁头移动到适当的扇区上);2 寻道时间(制动手臂移动,使得磁头移动到适当的磁道上);3 实际的数据传输时间。其中,寻道时间最长,因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。
  2. 先来先服务:1 按照磁盘请求的顺序进行调度;2 优点是公平和简单;3 缺点也很明显,因为未对寻道做任何优化,因此平均寻道时间可能较长;
  3. 最短寻道时间优先:1 优先调度与当前磁头所在磁道距离最近的磁道;2 虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现了饥饿现象,尤其是两端的磁道请求更容易出现饥饿现象;
  4. 电梯算法:1 电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向; 2 电梯算法和电梯的运行过程类似,总是按一个方向来进行磁盘调度,直到该方向上没有未完成的磁盘请求,然后改变方向;3 由于考虑了移动方向,因此所有的磁盘请求都会被满足,解决了饥饿问题;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hellosc01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值