操作系统是运行在计算机上管理计算机硬件与软件资源的软件程序。常见操作系统有:Windows、macOS 、Linux、IOS和Android。操作系统支持额外的扩展,比如 I/O 设备驱动和文件系统,支持按需装载,在UNIX/Linux中叫做共享库(.so,shared library),在Windows中则被称为动态链接库(.ddl,Dynamic Link Library)。
用户态(用户程序)通过系统调用(设备管理、文件管理、进程控制、进程通信、内存管理)申请使用系统态级别的资源,并由操作系统代为完成系统态的操作。
进程和线程都是在程序执行过程中的运行活动。
进程是系统资源分配的最小独立单位,线程是程序执行(CPU调度)的最小单位。
线程从属于进程,进程拥有独立的地址数据空间(一个进程死掉不影响另一个进程),线程共享进程的地址数据空间(一个线程死掉可能会导致整个进程被操作系统杀掉,进程占用资源多于线程)。
一个进程至少有一个运行代码的主线程。
多线程编程性能和体验更好,却对其余进程不友好(占用大量CPU资源)。
线程共享堆、全局变量、静态变量、文件等资源,独享栈和寄存器等资源。
创建状态(new) ——就绪状态(ready) (就差CPU 资源就可运行)——运行状态(running)
阻塞状态(waiting) (即等待状态,等待资源或IO操作完成)——结束状态(terminated) (正常结束或中断退出)。
无名管道:半双工通信(单向数据流动)且仅具有亲缘关系的进程通信(通过父进程fork出来的子进程),存在于内存;
有名管道:半双工通信(单向数据流动)且无论是否亲缘关系的进程通信,存在于磁盘;
信号:一种比较复杂的通信方式,用于通知接收进程某个事件已经发生
消息队列 :消息队列是内核中由消息队列标识符标识的消息构成的链表。消息队列克服了信号承载信息量少,管道只能承载无格式字节流和缓冲区大小受限等缺点。
信号量 :一个计数器,用于多进程对共享数据的访问,目的在于进程间同步并避免竞争条件。
共享内存:由一个进程创建的映射一段能被其他多个进程所访问的内存。往往配合其他通信机制(互斥锁、信号量)进行进程间同步(最快且最有用的进程间通信方式)。
套接字 : 可用套接字中的相关函数来完成通信过程,还可用于不同机器之间的进程。
目的在于确定进程的执行顺序,实现CPU最大利用率,算法有:
先到先服务: 按进程进入就绪队列的先后次序运行。
短进程优先: 选择就绪队列中估计运行时间最短的进程运行(优先照顾了短进程而忽略了长进程)。
时间片轮转 : 又称RR(Round robin)调度。每个进程均有一个时间片,即该进程允许运行的时间。超时送入就绪队列的队尾,换队首进程运行。
优先级 :每个进程分配(按内存、时间或其他资源)优先级,首先运行具有最高优先级的进程。相同优先级的进程以先到先服务方式运行。
高响应比:按照高响应比[(已等待时间 + 要求运行时间)/ 要求运行时间 ]优先的原则,等待时间越长或运行时间越短响应比越高。
多级反馈队列 :将就绪队列再划(进程性质和类型)分成子队列,不同子队列采用适合自己队列进程性质的调度算法。是较好的进程调度算法(UNIX操作系统采用)。
线程同步是两个或多个共享关键资源的线程在并发执行过程中避免资源冲突。方式:
互斥量:通过互斥对象具有唯一性,只有拥有互斥对象的线程才能访问公共资源。
信号量:通过控制同一时刻多个线程访问同一资源最大线程数量。
事件:通过通知操作的方式来保持多线程同步,便于实现多线程优先级的比较操作。
死锁是指两个或两个以上的进程在运行过程中因争夺资源或因彼此通信而造成的一一种阻塞的现象,若无外力作用,它们都将无法推进下去。这些永远在互相等待的进程称为死锁进程。 如下图所示:
死锁的发生必须具备以下四个必要条件:
死锁产生的两类原因:
解决死锁的基本方法:
安全性算法:判断分配给P1后剩余的资源,能不能使进程队列的某个进程执行完毕,若没有进程可执行完毕,则系统处于不安全状态(即此时没有一个进程能够完成并释放资源,随时间推移,系统终将处于死锁状态)。若存在进程P3可执行完毕,则假设P3执行完毕后回收已分配给它的资源并标记为可完成(剩余资源数量增加),然后继续判断队列中的其它进程,若所有进程都将能执行完毕,则系统处于安全状态,并根据可完成进程的分配顺序生成安全序列(如{P3,P0,P2,P1}表示将申请后的剩余资源先分配给P3–>回收–>分配给P0–>回收–>分配给P2–> 回收 —> 分配给 P1),否则不安全。
3. 检测死锁:为每个进程和每个资源指定一个唯一标识,并建立资源分配表和进程等待表
4. 解除死锁:即发现有进程死锁的同时立即把它从死锁状态中解脱出来。剥夺资源,即从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;撤消进程,即撤消死锁进程或撤消代价最小的进程(代价指优先级、运行代价、进程的重要性和价值等),直到有足够的资源可用和死锁状态消除为止。
并行(Parallelism):指程序的运行状态,在同一时间内有几件事情并行在处理。由于一个线程在同一时间只能处理一件事情,所以并行需要多个线程在同一时间执行多件事情。
并发(Concurrency):指程序的设计结构,在同一时间内多件事情能被交替地处理。重点是,在某个时刻只有一件事情在执行。比如单核 CPU 能实现多任务运行的过程就是并发。
阻塞(Blocking):阻塞是指调用在等待的过程中线程被挂起(CPU 资源被分配到其他地方去)。
非阻塞(Non-blocking):非阻塞是指等待的过程 CPU 资源还在该线程中,线程还能做其他的事情。
同步(Synchronous):各方都实时(或者尽可能实时)地收取(而且必要的话也处理或者回复)信息的即时沟通方式,即为同步。程序发出调用的时候,一直等待直到返回结果,没有结果之前不会返回。也就是,同步时调用者主动等待调用过程,且能立即得到结果的。
异步(Asynchronous):异步指两个或两个以上的对象或事件不同时存在或发生(或多个相关事物的发生无需等待其前一事物的完成)。程序发出调用之后,无法立即得到结果,需要额外的操作才能得到预期的结果是为异步。
单线程:从头执行到尾,逐行执行,如果其中一行代码报错,那么剩下代码将不再执行。同时容易代码阻塞。
多线程:代码运行的环境不同,各线程独立,互不影响,避免阻塞。多线程可能出现的问题:
内存管理涉及内存分配、回收和地址转换(逻辑地址转换为物理地址)。
连续分配管理:块式管理(块中容易形成未被利用的内存空间——碎片,内存利用率低下);
非连续分配管理:页式管理(页是物理信息单位,页表记录“逻辑—物理地址”的映射,内存利用率提高)、段式管理(将页细化成定义了逻辑信息的具有实际意义的段,段表)、段页式管理(先分段再分页)。
分页、分段目的都是提高内存利用率,减少内存碎片;
段之间、页之间均为离散存储,段之内、页之内均为连续的;
页大小固定,由操作系统决定;段取决于当前运行的程序,大小不固定;
分页(物理信息单位)仅为满足操作系统内存管理需求,而段(逻辑信息单位,体现为代码段/数据段)能更好满足用户需求。
为了解决虚拟地址到物理地址的转换速度,操作系统在页表方案基础之上引入了快表(页表的高速缓冲存储器(Cache),类似于redis 之于 mysql)来加速虚拟地址到物理地址的转换。若采用页表做地址转换,读写内存数据时CPU要访问两次主存。引入块表后,有时只需访问一次高速缓冲存储器和一次主存,这样可加速查找并提高指令执行速度。转换流程如下:
为了避免把全部页表(尤其是根本就不需要的页表)一直放在内存中占用过多空间,引入多级页表:将1级页表划分成若干个2级页表,1级页表中存储的是到2级页表的映射,对于没有使用的2级页表就可以不需要存储再内存中了,使得页表占用的内存空间大幅减少。
CPU采用虚拟寻址:将逻辑地址映射为物理地址(CPU中的内存管理单元MMU);虚拟地址允许一系列相邻的虚拟地址访问真实物理地址不连续的内存区域;虚拟地址允许访问大于可用物理内存的内存缓冲区(物理内存页+磁盘文件——当可用物理内存变小时内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件,数据或代码页会根据需要在该物理内存与磁盘之间移动);不同进程使用的虚拟地址彼此隔离,因为直接暴露物理地址(内存单元真实地址),会对操作系统造成伤害(若用户能访问任意物理内存,会影响到操作系统)和同时给运行多个程序造成困难(同时访问同一物理内存地址而崩溃);
虚拟内存定义了一个连续的虚拟(逻辑)地址空间(实际上被分隔成多个物理内存碎片或部分存储在外部磁盘存储器),并且把内存扩展到硬盘空间(Linux的交换空间,windows的虚拟内存)。
局部性原理:时间局部性 (高速缓存实现)——程序在某一段时间内访问同一数据或执行同一指令多次(产生于程序存在的循环操作)。空间局部性 ——程序在一段时间内所访问的可能是一定范围内的内存地址(产生于指令的顺序存放和顺序执行,数据的连续存储,比如数组等)
虚拟内存技术就是建立了 “内存一外存”的两级存储器的结构,利用局部性原理实现髙速缓存,程序运行时,动态将需要的部分调入内存,不需要的调入外存,是用时间(CPU计算时间 + 页调入调出时间)换空间(内外存)的方案。实现方式可以是:1. 请求分页存储管理(在页式管理基础上增加请求调页功能和页面置换功能,是目前最常用的实现虚拟内存的方式) 2.请求分段存储管理 3.请求段页式存储管理。
需执行的指令或数据未在内存,称为缺页/缺段;CPU通知操作系统OS将其调入内存的过程称为缺页中断。
Windows 采用的是分页式:在不考虑程序构造的情况下,把运行的程序按照一定大小(4KB)的页进行分割,并以页为单位进行置换。在分页式中,把磁盘的内容读到内存中称为 Page In,把内存的内容写入磁盘称为 Page Out。
为了实现虚拟内存功能,Windows在磁盘上提供了虚拟内存使用的文件(page file,页文件)。该文件由 Windows 生成和管理,文件的大小和虚拟内存大小相同,通常大小是内存的 1 - 2 倍。
缺页中断时将选择合适的内存中的页调出(即淘汰)置换所需外存中的页,页面置换算法目的是选择内存中合适的页淘汰掉。
PT页面置换算法(最佳页面置换算法) :不可实现的理想情况,一般作为衡量其他置换算法的方法。
FIFO(First In First Out)页面置换算法(先进先出页面置换算法) : 淘汰在内存中驻留时间最久的页。
LRU(Least Recently Used)页面置换算法(最近最久未使用页面置换算法) :赋予每页一个上次访问所经历的时间T字段,淘汰T值最大的页。
LFU(Least Frequently Used)页面置换算法(最近最少使用页面排序算法) : 不断维护一个按最近一段时间使用频率排序的页链表。缺页时淘汰链表尾节点的页。