什么是操作系统?
操作系统(os)是管理计算机硬件和软件资源的计算机程序,提供一个计算机用户与计算机硬件系统之间的接口。
向上对用户程序提供接口,向下接管硬件资源。
操作系统本质上也是一个软件,作为最接近硬件的系统软件,负责处理器管理、存储器管理、设备管理、文件管理和提供用户接口。
操作系统的内核(Kernel)是操作系统的核⼼部分,它负责系统的内存管理,硬件设备的管理,⽂件系统的管理以及应⽤程序的管理。 内核是连接应⽤程序和硬件的桥梁,决定着系统 的性能和稳定性。
用户态和内核态
两种CPU状态: 用户态:运行用户程序 内核态:运行操作系统程序,操作硬件 一般的操作系统对执行权限进行分级, 用户态相较于内核态有较低的执行权限,很多操作是不被操作系统允许的,原因简单来说就是用户态出现问题不会让操作系统崩溃。 内核态相当于一个介于硬件与应用之间的层,内核可以执行任何cpu指令,也可以引用任何内存地址,包括外围设备, 例如硬盘, 网卡,权限等级最高
运⾏的程序基本都是运⾏在⽤户态,如果我们调⽤操作系统提供的内核态级别的⼦功能就需要系统调用。
在我们运⾏的⽤户程序中,凡是与内核态级别的资源有关的操作(如⽂件管理、进程控制、内存管理等),都必须通过系统调⽤⽅式向操作系统提出服务请求,并由操作系统代为完成。
系统调⽤按功能⼤致可分为如下⼏类: 设备管理。完成设备的请求或释放,以及设备启动等功能。 ⽂件管理。完成⽂件的读、写、创建及删除等功能。 进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。 进程通信。完成进程之间的消息传递或信号传递等功能。 内存管理。完成内存的分配、回收以及获取作业占⽤内存区⼤⼩及地址等功能。
软中断和硬中断
从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器。
硬中断: 是由硬件产生的,比如,像磁盘,网卡,键盘等。每个设备或设备集都有它自己的IRQ(中断请求)。基于IRQ,CPU可以将相应的请求分发到对应的硬件驱动上。(硬件驱动通常是内核中的一个子程序,而不是一个独立的进程)
硬中断可以直接中断CPU。处理中断的驱动是需要运行在CPU上的,因此,当中断产生的时候,CPU会中断当前正在运行的任务,来处理中断。
软中断: 软中断是一些对I/O的请求。这些请求会调用内核中可以调度I/O发生的程序。软中断是通讯进程之间用来模拟硬中断的一种信号通讯方式。软中断是软件实现的中断,也就是程序运行时其他程序对它的中断。
软中断并不会直接中断CPU。也只有当前正在运行的代码(或进程)才会产生软中断。这种中断是一种需要内核为正在运行的进程去做一些事情(通常为I/O)的请求。
为了满足实时系统的要求,中断处理应该是越快越好。linux为了实现这个特点,当中断发生的时候,硬中断处理那些短时间就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断来完成
硬中断和软中断的区别
软中断是执行中断指令产生的,而硬中断是由外设引发的。
硬中断的中断号是由中断控制器提供的,软中断的中断号由指令直接指出,无需使用中断控制器。
硬中断是可屏蔽的,软中断不可屏蔽。
硬中断处理程序要确保它能快速地完成任务,这样程序执行时才不会等待较长时间,称为上半部。
软中断处理硬中断未完成的工作,是一种推后执行的机制,属于下半部。
进程和线程
进程:是程序的一次执行过程,是系统进行资源分配的基本单位。
线程:是一个程序内部的一条执行路径。是操作系统能够进行运算调度的最小单位。程序执行的最小单位。进程可以细化为多个线程。
线程和进程最⼤的不同在于基本上各进程是独⽴的,⽽各线程则不⼀定,因为同⼀进程中的线程极有可能会相互影响。
从另⼀⻆度来说,进程属于操作系统的范畴,主要是同⼀段时间内,可以同时执⾏⼀个以上的程序,⽽线程则是在同⼀程序内⼏乎 同时执⾏⼀个以上的程序段。线程执⾏开销⼩,但不利于资源的管理和保护;⽽进程正相反。
线程不拥有系统资源,但可以访问隶属于进程的资源.
线程共享进程的内存空间。用户级线程与内核无关
协程:一个线程可以有多个协程。 一个线程内的多个协程的运行是串行的当线程内的某一个协程运行时,其它协程必须挂起。由于协程切换是在线程内完成的,涉及到的资源比较少。
协程与线程的区别:
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。从技术的角度来说,“协程就是你可以暂停执行的函数”。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程。
2) 线程进程都是同步机制,而协程则是异步。
3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。 4) 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。 5) 协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程.。 6) 线程是协程的资源。协程通过Interceptor来间接使用线程这个资源。
进程上下文切换
上下文切换(有时也称做进程切换或任务切换)是指 CPU 从一个进程或线程切换到另一个进程或线程。
进程的上下文: 不但包括虚拟内存、栈、全局变量等用户空间资源,还包括内核堆栈、寄存器等内核空间状态。
进程间的通信⽅式
七种,是同一台设备上的进程通信,不同设备上的需要网络通信。
管道/匿名管道:用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
有名管道:匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循先进先出,以磁盘文件的方式存在,可以实现本机任意两个进程通信。
信号:一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
消息队列:消息队列是消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号量:是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信⽅式主要⽤于解决与同步相关的问题并避免竞争条件。
共享内存:使得多个进程可以访问同一块内存空间,需要依靠同步操作,比如互斥锁和信号量等。
套接字Sockets:主要用在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的⽹络通信的基本操作单元,可以看做是不同主机之间的进程进⾏双向通信的端点,简单的说就是通信的两⽅的⼀种约定,⽤套接字中的相关函数来完成通信过程。与其他通信机制不同的是,它可用于不同机器间的进程通信
1.管道:速度慢,容量有限,只有父子进程能通讯 2.FIFO:任何进程间都能通讯,但速度慢 3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题 4.信号量:不能传递复杂消息,只能用来同步 5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存
线程间的同步的方式
线程同步是两个或多个共享关键资源的线程的并发执⾏。应该同步线程以避免关键的资源使⽤冲突。操作系统⼀般有下⾯三种线程同步的⽅式:
1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问。
2.互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如Synchronized关键字和各种Lock。
3.信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
4.事件:通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作。
临界区的效率是最高的,因为它不是内核对象,而其它的三个都是核心对象,要借助操作系统来实现,效率相对来说就比较低。但如果要跨进程使用还是要用到互斥器、事件对象和信号量。临界区(critical section)只能在进程内部各线程间使用.
进程的调度算法
为了确定⾸先执⾏哪个进程以及最后执⾏哪个进程以实现最⼤ CPU 利⽤率,计算机科学家已经定义了⼀些算法。
先到先服务(FCFS):从就绪队列中选择⼀个最先进⼊该队列的进程给它分配资源, 使它⽴即执⾏并⼀直执⾏到完成或发⽣某事件⽽被阻塞放弃占⽤ CPU 时再重新调度。
短作业优先(SJF):从就绪队列中选出⼀个估计运⾏时间最短的进程为之分配资源,使它⽴即执⾏并⼀直执⾏到完成或发⽣某事件⽽被阻塞放弃占⽤ CPU 时再重新调度。
时间片轮转(RR):最古⽼,最简单,最公平且使⽤最⼴的算法。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
多级反馈队列:既能使高优先级的作业得到响应⼜能使短作业(进程)迅速完成。公认的⼀种较好的进程调度 算法,UNIX 操作系统采取的便是这种调度算法。
优先级调度:为每个流程分配优先级,⾸先执⾏具有最⾼优先级的进程,依此类推。具有 相同优先级的进程以 FCFS ⽅式执⾏。可以根据内存要求,时间要求或任何其他资源要求来 确定优先级。
内存管理
操作系统的内存管理主要负责内存的分配与回收(malloc函数:申请内存,free函数:释放内存)
常见的几种内存管理机制:
连续分配内存: 块式管理:内存分为几个固定大小的块,每个块中只包含一个进程。 内存碎片问题:在分配单元之间和分配单元内部不能被利用的空闲内存(外碎片和内碎片) 压缩式碎片整理和交换式碎片整理 非连续分配内存: 提出原因: 连续内存分配的缺点:分配给一个程序的物理内存是连续的,内存利用率低;有外碎片、内碎片的问题。 非连续分配的优点:非连续的,更好的内存利用和管理;允许共享代码与数据;支持动态加载和动态链接 管理方式:分段和分页,段页式管理 分页:把主存分为⼤⼩相等且固定的⼀⻚⼀⻚的形式,⻚较⼩,相⽐于块式管理的划分⼒度更⼤,⻚式管理通过⻚表对应逻辑地址和物理地址。划分物理内存至固定大小的帧,大小是2的幂;划分逻辑地址空间至相同大小的页 分段:⻚式管理虽然提⾼了内存利⽤率,但是⻚式管理其中的⻚实际并⽆任何实际意义。 段式管理把主存分为⼀段段的,每⼀段的空间⼜要⽐⼀⻚的空间⼩很多 。但是,最重要的是段是有实际意义的,每个段定义了⼀组逻辑信息,例如,有主程序段 MAIN、⼦程序段X、数据段 D 及栈段 S等。 段式管理通过段表对应逻辑地址和物理地址。 段表有两个重要信息:段的起始地址,段的长度限制 段⻚式管理:结合了段式管理和⻚式管理的优点。简单来说段⻚式管理机制就是把主存先分成若⼲段,每个段⼜分成若⼲⻚,也就是说 段⻚式管理机制 中段与段之间以及段的内部的都是离散的。
快表和多级页表
快表:加速虚拟地址到物理地址的转换
把常用的页表项缓存到CPU中,不需要多次访问内存,提高速度
使⽤快表之后的地址转换流程是这样的: 1. 根据虚拟地址中的⻚号查快表; 2. 如果该⻚在快表中,直接从快表中读取相应的物理地址; 3. 如果该⻚不在快表中,就访问内存中的⻚表,再从⻚表中得到物理地址,同时将⻚表中的该 映射表项添加到快表中; 4. 当快表填满后,⼜要登记新⻚时,就按照⼀定的淘汰策略淘汰掉快表中的⼀个⻚。
(跟redis缓存的原理很像。)
多级页表
引⼊多级⻚表的主要⽬的是为了避免把全部页表一直放在内存中占用过多空间。时间换空间
当前页表的页表项是下一级页表,形成页表树(比如二级页表,内存中只用存一级页表和程序实际占用页面对应的二级页表项)
反向页表:大地址空间问题,前向映射页表很繁琐;让页表与物理地址空间的大小相对应。
逻辑(虚拟)地址空间增长速度快于物理地址空间
分页机制和分段机制的区别
共同点: 分页机制和分段机制都是为了提高内存利用率,减少内存碎片。 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。 区别 : 1.页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。 2.分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。
虚拟(逻辑)地址和物理地址
编程里面提到的地址一般指的就是逻辑地址,比如C语言里指针存储的就是逻辑地址,Java栈里引用存的也是对象的逻辑地址,逻辑地址是由操作系统分配的。物理地址指的是真实物理内存中的地址,具体来说就是内存地址寄存器中的地址。物理地址是内存单元真正的地址。
映射关系
CPU寻址
现代处理器使用的是一种称为虚拟寻址的寻址方式。使用虚拟寻址,CPU需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。实际上完成虚拟地址转换为物理地址的硬件是CPU中的内存管理单元(MMU)。
为什么需要虚拟地址空间?
如果没有虚拟地址空间,程序直接访问和操作的是物理内存。直接把物理地址暴露出来可能对操作系统造成伤害以及给同时运行多个程序造成困难。
通过虚拟地址访问内存的优势:
1.程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
2.程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。 当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。 数据或代码页会根据需要在物理内存与磁盘之间移动。
3.不同进程使⽤的虚拟地址彼此隔离。⼀个进程中的代码无法更改正在由另⼀进程或操作系统使⽤的物理内存。
虚拟内存
虚拟内存的重要意义是它定义了⼀个连续的虚拟地址空间,并且把内存扩展到硬盘空间。
通过虚拟内存可以让程序可以拥有超过系统物理内存⼤⼩的可⽤内存空间。另外,虚拟内存为每个进程提供了⼀个⼀致的、私有的地址空间,它让每个进程产⽣了⼀种⾃⼰在独享主存的错觉(每个进程拥有⼀⽚连续完整的内存空间)。这样会更加有效地管理内存并减少出错。
实际上虚拟内存是映射在多个物理内存碎片上,还有部分映射到了外部磁盘存储器上。
虚拟内存有以下两个优点:
1.虚拟内存地址空间是连续的,没有碎片
2.虚拟内存的最大空间就是cup的最大寻址空间,不受内存大小的限制,能提供比内存更大的地址空间
局部性原理
局部性原理是虚拟内存技术的基础,正是因为程序运⾏具有局部性原理,才可以只装⼊部分程序到内存就开始运⾏。
局部性原理表现在以下两个⽅⾯:
-
时间局部性 :如果程序中的某条指令⼀旦执⾏,不久以后该指令可能再次执⾏;如果某数据被访问过,不久以后该数据可能再次被访问。产⽣时间局部性的典型原因,是由于在程序中存在着⼤量的循环操作。
-
空间局部性 :⼀旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问, 即程序在⼀段时间内所访问的地址,可能集中在⼀定的范围之内,这是因为指令通常是顺序存放、顺序执⾏的,数据也⼀般是以向量、数组、表等形式簇聚存储的。
时间局部性是通过将最近使用的指令和数据保存到⾼速缓存存储器中,并使⽤⾼速缓存的层次结构实现。空间局部性通常是使用较大的⾼速缓存,并将预取机制集成到⾼速缓存控制逻辑中实现。虚拟内存技术实际上就是建⽴了 “内存⼀外存”的两级存储器的结构,利⽤局部性原理实现髙速缓存。
虚拟存储器
基于局部性原理,在程序装⼊时,可以将程序的⼀部分装⼊内存,⽽将其他部分留在外存,就可 以启动程序执⾏。
在程序执⾏过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调⼊内存,然后继续执⾏程序。另⼀⽅⾯,操作系统将内存中暂时不使⽤的内容换到外存上,从⽽腾出空间存放将要调⼊内存的信息。这样,计算机好像为⽤户提供了⼀个⽐实际内存⼤的多的存储器——虚拟存储器。
其实虚拟内存同样是⼀种时间换空间的策略,你⽤ CPU 的计算时间,⻚的调⼊调出 花费的时间,换来了⼀个虚拟的更⼤的空间来⽀持程序的运⾏。
虚拟内存的技术实现
虚拟内存的实现需要建⽴在离散分配的内存管理⽅式的基础上。虚拟内存的实现有以下三种⽅式:
-
请求分⻚存储管理:建⽴在分⻚管理之上,增加了请求调⻚功能 和⻚⾯置换功能。
请求分⻚是⽬前最常⽤的⼀种实现虚拟存储器的⽅法。在请求分⻚存储管理中,在作业开始运⾏之前,仅装⼊当前要执⾏的部分页即可运⾏。假如在作业运⾏的过程中发现要访问的⻚⾯不在内存,则由处理器通知操作系统按照对应的⻚⾯置换算法将相应的⻚⾯调⼊到主存,同时操作系统也可以将暂时不⽤的⻚⾯置换到外存中。
-
请求分段存储管理:建⽴在分段存储管理之上,增加了请求调段功能、分段置换功能。
-
请求段页式存储管理
请求分⻚与分⻚存储管理,两者有何不同
请求分⻚存储管理建⽴在分⻚管理之上。他们的根本区别是是否将程序全部所需的全部地址空间 都装⼊主存,这也是请求分⻚存储管理可以提供虚拟内存的原因。
页面置换算法
地址映射过程中,若在⻚⾯中发现所要访问的⻚⾯不在内存中,则发⽣缺⻚中断。
缺⻚中断就是要访问的⻚不在主存,需要操作系统将其调⼊主存后再进⾏访问。 在这个时 候,被内存映射的⽂件实际上成了⼀个分⻚交换⽂件。
当发⽣缺⻚中断时,如果当前内存中并没有空闲的⻚⾯,操作系统就必须在内存选择⼀个⻚⾯将其移出内存,以便为即将调⼊的⻚⾯让出空间。⽤来选择淘汰哪⼀⻚的规则叫做⻚⾯置换算法, 我们可以把⻚⾯置换算法看成是淘汰⻚⾯的规则。
有哪些页面置换算法:
最佳⻚⾯置换算法OPT:所选择的被淘汰 ⻚⾯将是以后永不使⽤的,或者是在最⻓时间内不再被访问的⻚⾯,这样可以保证获得最低的缺⻚率。⽽该算法⽆法实现。⼀般作为衡量其他置换算法的⽅法。
先进先出FIFO:: 总是淘汰最先进⼊内 存的⻚⾯,即选择在内存中驻留时间最久的⻚⾯进⾏淘汰。
最近最久未使用LRU:赋予每个⻚⾯⼀个访问字段,⽤来记录⼀个⻚⾯⾃上次被访问以来所经历的时间 T,淘汰⻚⾯时,选择T 值最⼤的,即最近最久未使⽤的⻚⾯予以淘汰。
最少使用LFU:选择在之前时期使⽤最少的页面作为淘汰页。