操作系统核心概念总结

Posted by 彭超 on 2020-07-25
Estimated Reading Time 18 Minutes
Words 5.6k In Total
Viewed Times

操作系统基础

什么是操作系统

操作系统是管理 计算机硬件软件资源 的程序,是计算机系统的内核与基石,本质上是运行在计算机上的软件程序,为用户提供一个与系统交互的操作界面。它分为内核和外壳,内核是能操作硬件的程序,而外壳即围绕着内核的应用程序。

什么是系统调用

介绍系统调用之前,先了解一下 用户态系统态。根据进程访问资源的特点,可以把进程在系统上的运行分为以下两个级别:

  1. 用户态:运行的进程可以直接读取用户程序的数据。
  2. 系统态:运行的进程几乎可以直接访问计算机的任何资源,不受限制。

我们使用的程序基本都是运行在用户态,如果调用操作系统提供的系统态级别功能,那就需要系统调用了。也就是说我们使用的程序中,只要是与系统态级别的相关资源(如文件管理、进程控制、内存管理等)的操作,都必须通过系统调用方式提出服务请求,并由操作系统代为完成。这些系统调用功能大致可分为以下几类:

  • 设备管理:完成设备的请求、启动或释放等功能。
  • 文件管理:完成文件的读、写、创建及删除等功能。
  • 进程控制:完成进程的创建、撤销、阻塞及唤醒等功能。
  • 进程通信:完成进程之间的消息传递或信号传递等功能。
  • 内存管理:完成内存的分配、回收以及获取作业占用内存区大小及地等功能。

进程和线程

进程和线程的区别

下图是 Java 内存区域,我们从 JVM 的角度说一下线程和进程之间的关系。

从上图可以看出,一个进程中可以有多个线程,多个线程共享进程的 方法区(JDK8 之后的元空间) 资源,但是每个线程有自己的 虚拟机栈本地方法栈程序计数器

总的来说,进程和线程有以下几点区别:

  • 线程是进程划分的更小的运行单位,一个进程在其执行的过程中可以产生多个线程。
  • 各进程是独立的,而各线程则不一定,因为同一进程中的线程可能会相互影响。
  • 线程执行开销小,但不利于资源的管理和保护,而进程则相反。

进程的几种状态

一般把进程大致分为 5 种状态:

  1. 创建状态(new:进程正在被创建。
  2. 就绪状态(ready:进程已处于准备运行状态。即进程得到了除处理器之外的一切资源,一旦得到处理器资源即可运行。
  3. 运行状态(running:进程正在处理器上运行(单核 CPU 下任何时刻只有一个进程处于运行状态)。
  4. 阻塞状态(waiting:等待状态,进程正在等待某一事件而暂停运行(如等待某资源可用)。即使处理器空闲,该进程也不能运行。
  5. 结束状态(terminated:进程正在从系统中消失。可能是进程正常结束或其他原因中断退出运行。

进程间的通信方式

  • (匿名)管道:用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。

  • 有名管道:匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循先进先出。有名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。

  • 信号:信号是一种比较复杂的通信方式,用于通知接受进程某个时间已经发生。

  • 消息队列:消息队列是消息的链表,具有特定的格式,存放在内存中并由详细队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道不同的是消息队列存放在内核中,只有在内核重启或者显示地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

  • 信息量:信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。

  • 共享内存:使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。

  • 套接字:此方法主要用于客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信两方的一种约定,用套接字中的相关函数来完成通信过程。

线程间的同步方式

线程同步是两个或多个共享关键资源的线程的并发执行。应该同步线程以避免关键的资源使用冲突。操作系统一般有下面三种线程同步的方法:

  1. 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
  2. 信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
  3. 事件:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。

进程的调度算法

  • 先到先服务调度算法:从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。

  • 短作业优先的调度算法:从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。

  • 时间片转轮调度算法:时间片轮转调度是一种最古老、最简单、最公平且使用最广的算法。每个进程被分配一个时间段,称作它为时间片,即该进程允许运行的时间。

  • 多级反馈队列调度算法:前面介绍的

  • 优先级调度:为每个流程分配优先级,首先执行具有最高优先级的进程,以此类推。可以根据内存要求、时间要求或任何其它资源要求来确定优先级。

内存管理基础

内存管理介绍

操作系统的内存管理主要负责 内存的分配与回收,另外地址转换也就是将逻辑地址转换成相应的物理地址等功能。

常见的几种内存管理机制

简单分为 连续分配管理方式非连续分配管理方式 这两种。连续分配管理方式 是指为一个用户程序分配一个连续的内存空间,常见的的如 块式管理非连续分配管理方式 允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如 页式管理段式管理

  • 块式管理:将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎就浪费了。这些在每个块中未被利用的空间称之为碎片。
  • 页式管理:把内存分为大小相等且固定的一页一页形式,页较小,相比于块式管理的划分粒度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
  • 段式管理:把内存分为一段段的,每一段的空间又比一页的空间小很多。每个段定义了一组逻辑信息,例如主程序 MAIN、子程序段 X、数据段 D 及 栈段 S 等。
  • 段页式管理:结合了段式管理的页式管理的优点。把内存先分成若干段,每段又分成若干页,也就是说段与段之间以及段的内部都是离散的。

快表和多级页表

页表管理机制中有两个很重要的概念:快表和多级页表。

在分页内存管理中,很重要的两点是:

  1. 虚拟地址到物理地址的转换要快。
  2. 解决虚拟地址空间大,页表也会很大的问题。
  • 快表:为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的告诉缓冲存储器,其中的内容是页表的一部分或者全部内容,提高了访问速率。由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存,而有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。

    转换地址流程如下:

    1. 根据虚拟地址中的页号查快表。
    2. 如果该页在快表中,直接从快表中读取相应的物理地址。
    3. 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中。
    4. 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一页。

    看完了之后会发现快表和我们平常经常开发时使用的缓存(比如 Redis)很像。

  • 多级页表:引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景。

总结:为了提高内存的空间性能,提出了多级页表的概念。但是提到空间性能是以浪费时间性能为基础的,因此为了补充损失的时间性能,提出了快表的概念。不论是快表还是多级页表实际上都利用了程序的局部性原理。

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

  • 共同点:分页机制和分段机制都是为了提高内存利用率,较少内存碎片。页和段都是离散存储的,所以两者都是离散分配内存的方式,但是,每个页和段中的内存是连续的。
  • 区别:页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。其次,分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段、数据段,能够更好满足用户的需要。

逻辑(虚拟)地址和物理地址

比如在 C 语言中,指针里面存储的数值可以理解成为内存里的一个地址,这个地址也就是我们说的逻辑地址,逻辑地址由操作系统决定。物理地址指的是真实物理内存中地址,更具体一点来说就是内存地址寄存器中的地址。物理地址是内存单元真正的地址。

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

现代处理器使用的是一种称为 虚拟寻址 的寻址方式,使用虚拟寻址,CPU 需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。实际上完成虚拟地址转换为物理地址的硬件是 CPU 中一个被称为 内存管理单元 的硬件。

再说说为什么需要虚拟地址空间?

没有虚拟地址空间的时候,程序都是直接访问和操作 物理内存。这会导致以下问题:

  1. 用户程序可以访问任意内存,寻址内存的每个字节,这样就很容易破坏操作系统,造成操作系统奔溃。
  2. 想要同时运行多个程序特别困难,比如同时运行一个微信和一个 QQ 都不行,因为微信在运行的时候给内存地址 1xxx 赋值后,QQ 也同样给内存地址 1xxx 赋值,那么 QQ 对内存的赋值就会覆盖微信之前所赋的值,这就造就了微信这个程序奔溃。

总结:如果直接把物理地址暴露出来的话会带来严重问题,比如可能对操作系统造成伤害以及给同时运行多个程序造成困难。

通过虚拟地址访问内存有以下优势:

  1. 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
  2. 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页保存到磁盘文件。
  3. 不同进程使用的虚拟地址彼此隔离,一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。

虚拟内存

什么是虚拟内存?

通过虚拟内存可以让程序可以拥有超过系统物理内存大小的可用内存空间。并且虚拟内存为每个进程提供了一个一致的、私有的地址空间。

虚拟内存是计算机系统内存管理的一种技术,我们可以手动设置自己电脑的虚拟内存。虚拟内存的重要意义是它定义了一个连续的虚拟地址空间,并且把内存扩展到硬盘空间。

局部性原理

局部性原理是虚拟内存技术的基础,正是因为程序运行具有局部性原理,才可以只装入部分程序到内存就开始运行。

局部性原理表现在以下两方面:

  1. 时间局部性:如果程序中的某条指令一旦执行,不久以后该指令可能再次执行;如果某数据被访问过,不久以后该数据可能再次被访问。产生时间局部性的典型原因是由于在程序中存在着大量的循环操作。
  2. 空间局部性:一旦程序访问了某个存储单元,在不久之后,其附件的存储单元也将被访问,即程序在一段时间内所访问的地址,可能几种在一定的范围之内,这是因为指令通常是顺序存放、顺序执行的,数据也一般以向量、数组、表等形式存储的。

时间局部性是通过将近来使用的指令和数据保存到高速缓存存储器中,并使用高速缓存的层次结构来实现。空间局部性通常是使用较大的高速缓存,并将预期机制集成到高速缓存控制逻辑中实现。虚拟内存技术实际上就是建立了”内存—外存“的两级存储器的结构,利用局部性原理实现高速缓存。

虚拟存储器

基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其它部分留在外存,就可以启动程序执行。由于外存往往比内存大很多,所以我们运行的软件的内存大小实际上是可以比计算机系统实际的内存大小大的。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换到外存上,从而腾出空间存放将要调入内存你的信息。这样,计算机好像为用户提供了一个比实际内存大的多的存储器—虚拟存储器。

虚拟内存的技术实现

虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。

  1. 请求分页存储管理:建立在分页管理之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。请求分页存储管理系统中,在作业开始之前,仅装入当前要执行的部分段即可运行。加入在作业运行的过程中发现要访问的页面不在内存中,则由处理器通知操作系统按照对应的页面置换算法将相应的页面调入到主存,同时操作系统也可以将暂时不用的页面置换到外存中。
  2. 请求分段存储管理:建立在分段式存储管理之上,增加了请求调段功能、分段置换功能。请求分段储存管理方式就如同前期请求分页储存管理方式一样,在作业开始运行之前,仅装入当前要执行的部分段即可运行;在执行过程中,可使用去请求调入中断动态装入要访问但又不在内存的程序段;当内存空间已满,而又要装入新的段时,根据置换功能适当调出某个段,以便腾出空间而装入新的段。
  3. 请求段页式存储管理

请求分页存储器管理建立在分页管理之上,他们的根本区别在于是否将程序全部所需的全部地址空间都装入主存,这也是请求分页存储管理可以提供虚拟内存的原因。

它们之间的根本区别在于是否将一作业的全部地址空间同时装入主存。请求分页存储管理不要求将作业全部地址空间同时装入主存。基于这一点,请求分页存储管理可以提供虚存,而分页存储管理却不能提供虚存。

不管是上面哪种实现方式,一般都需要以下几点:

  1. 一定容量的内存和外存:在载入程序的时候,只需要将程序的一部分装入内存,而将其他部分留在外存,然后程序就可以执行了。
  2. 缺页中断:如果需执行的指令或访问的数据尚未在内存,则由处理器通知操作系统将相应的页面或段调入到内存,然后继续执行程序。
  3. 虚拟地址空间:逻辑地址到物理地址的交换。

页面置换算法

地址映射过程中,若在页面中发现所要访问的页面不在内存中,则发生缺页中断。

缺页中断:指要访问的页不在主存,需要操作系统将其调入主存后再进行访问。在这个时候,被内存映射的文件实际上成了一个分页交换文件。

当发生缺页中断时,如果当前内存中并没有空闲的画面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来选择淘汰哪一项的规则叫做 页面置换算法,我们可以把页面置换算法看成是淘汰页面的规则。

  • OPT 页面置换算法(最佳):所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。
  • FIFO 页面置换算法(先进先出):总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
  • LRU 页面置换算法(最近最久未使用):LRU 算法赋予每个页面一个访问字段,用来记录一个页面自上次访问以来所经历的时间 T,当须淘汰一个页面时,选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。
  • LFU 页面置换算法(最少使用):选择在之前时期使用最少的页面作为淘汰页。

If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !