操作系统
什么是操作系统?
操作系统,operating system,是管理计算机硬件与软件资源的程序,是计算机的基石。
操作系统屏蔽了硬件层的复杂性,操作系统就像是硬件使用的负责人,统筹着各种相关事项。
操作系统的内核是操作系统的核心部分,它负责系统的内存管理,硬件设备的管理,文件系统的管理和应用程序的管理。
操作系统的功能
- 进程和线程的管理:进程的创建、撤销、阻塞、唤醒、进程间通信等。
- 存储管理:内存的分配和管理、外存(磁盘等)的分配和管理等。
- 文件管理:文件的读写、创建删除等。
- 设备管理:完成设备的请求或释放、启动等功能。
- 网络管理:操作系统管理计算机网络的配置、连接、通信和安全等。
- 安全管理:用户的身份认证、访问控制、文件加密等。
用户态和内核态
根据进程访问资源的特点,我们可以把进程在系统中的运行分成两个级别:
- 用户态(User Mode):用户态的进程可以直接读取用户程序的数据,拥有较低的权限。应用程序需要执行有特殊权限的操作,就需要向操作系统发起系统调用请求,进入内核态。
- 内核态(Kernel Mode):内核态运行的进程几乎可以访问计算机的任何资源,包括系统的内存空间、设备、驱动程序等,权限非常高。当操作系统接收到进程的系统调用请求,就会从用户态切换到内核态,执行响应的系统调用,返回结果给进程,再从内核态切换回用户态。
为什么要有用户态和内核态?单独一个内核态不行吗?
在CPU的所有指令中,像内存分配、时钟设置、IO处理等,如果所有的程序都能用这些指令的话,会影响系统的正常运行。我们必须限制这些危险指令只能在内核态运行。这些只能由操作系统内核态执行的指令也叫特权指令。
用户态的程序只能访问自己的内存空间,试图访问其他内存区域会触发硬件异常。内核会对所有用户态请求进行校验,拒绝非法操作。
用户态和内核态的分离是操作系统的基石,它通过权限隔离和受控访问解决了以下问题:
资源竞争:内核统一调度资源(如CPU、内存),避免程序间直接冲突。
安全性:限制用户态程序的权限,防止恶意操作。
稳定性:保护内核关键数据不被破坏,确保系统可靠运行。
用户态切换到内核态有三种方式:
- 系统调用(trap):用户态进程主动要求切换到内核态。
- 中断(interrupt):外围设备完成用户请求的操作后,向CPU发起相应的中断信号,此时CPU会暂停执行下一条指令,转而执行跟中断信号对应的处理程序。如果先前指令在用户态执行,自然发生了用户态到内核态的切换。
- 异常(exception):当CPU在执行用户态下的程序时,发生了某些事先不可知的异常,就会转换成内核态,如缺页异常。
中断并不是贬义词,操作系统内部维护了一个中断向量表,记录着中断类型和对应的处理程序。
系统调用
用户态需要调用内核态级别的子功能,就需要发起系统调用。
系统调用大概分为四类:设备管理、文件管理、进程管理、内存管理。
系统调用的过程:
- 用户态程序发起系统调用,因为系统调用涉及特权指令,用户态权限不足,就会发生trap中断,跳转到中断处理程序,内核程序开始执行,处理系统调用。
- 系统调用处理完成,操作系统用特权指令切换回用户态,恢复用户态的上下文,继续执行用户程序。
进程和线程
进程是系统分配资源的基本单位,线程是轻量级进程,是操作系统进行调度的基本单位。
为什么有了进程还要有线程?
- 线程切换的开销很低,轻量化,一个进程可以有多个线程。
- 多个线程可以并发执行不同任务,有效利用多核心CPU。
- 同一个进程的线程共享内存和文件,相互通信无需调用内核。
PCB
PCB,即为Process Control Block,进程控制块,是管理和跟踪进程的数据结构。每个进程都对应着一个独立的PCB。
当操作系统创建进程时,会为进程分配一个唯一的进程ID,并为进程创建一个对应的PCB。
PCB中主要有:进程的描述信息,如名字、标识符;进程的调度信息,进程优先级;进程对资源的需求情况;进程打开的文件信息;处理及的状态信息。
进程状态
进程大致分为五种状态:
- 创建状态:new,进程正在被创建,尚未就绪
- 就绪状态:ready,等待被分配处理器资源
- 运行状态:running,进程正在处理器上运行
- 阻塞状态:waiting,又称为等待状态
- 结束状态:terminated,进程正在从系统中消失
进程间的通信方式有哪些?
- 匿名管道:Pipes,用于具有亲缘关系的父子进程之间的通信。
- 有名管道:Named Pipes,匿名管道因为没有名字,只能用于亲缘进程之间的通信,为了克服这个缺点而有了有名管道,严格遵循FIFO,以磁盘文件的方式存在,可以实现任意两个进程间的通信。
- 信号:signal
- 消息队列:Message Queuing,消息队列是消息的链表,也遵循先进先出。
- 信号量:Semaphores,信号量是一个计数器,用于多进程对共享数据的访问。
- 共享内存:Share Memory,使得多个进程可以访问同一块内存空间。但是需要考虑同步问题。
- 套接字:Sockets,主要用于在客户端和服务端之间通过网络进行通信。
进程调度算法
- 先来先服务:FCFS,first come first service
- 短作业优先:SJF,short job first。缺点是长作业容易饥饿
- 时间片轮转调度算法:RR,round-robin。公平,每个进程被分配一个时间段,称为时间片
- 多级反馈队列调度算法:MFQ,multi level feed back queue,目前公认的一种较好的进程调度算法。
- 优先级调度算法:Priority,为每个进程分配优先级,优先执行最高优先级进程。
什么是僵尸进程和孤儿进程
- 僵尸进程 子进程已经终止,但是父进程没有,且父进程没有调用wait或者waitpid等系统调用来获取子进程的状态信息,释放子进程的资源,导致子进程的PCB一直在系统中,但无法被进一步使用。为了避免僵尸进程的产生,父进程需要及时调用wait或者waitpid系统调用来回收子进程
- 孤儿进程 一个进程的父进程终止,但是它本身依然存在,失去了父亲进程。为了避免孤儿进程占用系统资源,操作系统会将孤儿进程的父进程设置为 init 进程(进程号为 1),由 init 进程来回收孤儿进程的资源。
死锁
产生死锁的四个必要条件
- 互斥:资源必须是非共享的,每次只有一个进程可以访问资源。
- 占有且等待:一个进程占有着临界区资源,此时有其他进程申请,且必须等待拥有资源的进程释放资源。
- 不可抢占:拥有临界资源的进程,不可以被其他进程抢占这个临界区资源。
- 循环等待:有一组相互等待的进程,互相等待其他进程释放资源。
内存管理:
内存管理主要做什么?
- 内存的分配和回收:对进程需要的内存进行分配和释放
- 地址转换:把程序中的虚拟地址转换成物理地址
- 内存扩充:系统内存不足,利用虚拟内存技术或自动覆盖技术,从逻辑上扩充内存
- 内存映射:将一个文件直接映射到进程的进程空间中,这样可以通过内存指针用读写内存的办法直接存取文件内容,速度更快。
- 内存优化:通过调整内存分配策略和回收算法优化内存使用效率
- 内存安全:保证进程之间使用内存互不干扰,避免一些恶意程序破坏。
内存碎片
- 内部内存碎片:假如程序只需要65KB内存,但是分配了128KB,那些没被用上的内存就是内部内存碎片
- 外部内存碎片:由于未分配的连续内存区域太小,满足不了进程所需要的内存分配请求。这些小片段且不连续的内存空间被称为外部内存碎片
常见的内存管理方式
主要分为连续内存管理和非连续内存管理。
连续内存管理就是给一个用户程序分配一片连续的内存空间,这种内存分配率一般不高,有严重的内存碎片问题。非连续的内存管理更灵活。
非连续内存管理:
- 段式管理:以段(一段连续的物理内存)的形式管理/分配物理内存。应用程序的虚拟地址被分为大小不等的段。
- 页式管理:把物理内存分成连续等长的物理页,然后应用程序的虚拟地址空间也被划分为连续等长的虚拟页。
- 段页式管理:结合了段和页。
虚拟内存
虚拟内存,virtual memory,是计算机系统内存管理非常重要的一个技术,本质上说它只是逻辑存在的,是假想出来的内存空间,主要作用是作为进程访问主存的桥梁并简化内存管理。
作用:
- 隔离进程:物理内存通过虚拟的地址空间访问。进程之间彼此隔离。一个进程中的代码无法更改另一个进程正在使用的物理内存。
- 提升物理内存利用率:有了虚拟地址空间后,操作系统只需要把当前进程正在使用的部分数据加载到物理内存中。
- 简化内存管理:程序员不和真正物理内存打交道,借助虚拟地址空间访问物理内存,简化内存管理。
- 多个进程共享物理内存:进程运行的时候会加载许多操作系统的动态库。这些库是共用的,在内存中实际只会加载一份,被称为共享内存。
- 提高内存安全性:控制进程对物理内存的访问,提高系统安全性
- 提供更大内存空间:可以让程序有超过系统物理内存大小的可用内存空间。也就是利用磁盘,把物理内存页放到磁盘里。
操作系统通过MMU:memory management unit来把虚拟地址转换成物理地址。
TLB是什么?
为了提高虚拟地址到物理地址的转换速度。操作系统在页表方案之上引入了转址旁路缓存Translation lookaside buffer,TLB。
主流的x86-65体系结构下,TLB属于MMU内部的单元。可以简单看成存储着虚拟页号和物理页号的哈希表。
使用TLB流程:
- 用虚拟地址的虚拟页号作为key在TLB中查询。
- 如果查到了,说明TLB命中,就不需要再访问页表了。
- 如果查不到,还是要到内存中查询页表,同时把查到的项添加到TLB中。
- TLB填满了,又要添加新页,就涉及各种淘汰策略了。
由于页表本身在内存中。在没有TLB之前,每次读写内存数据,CPU要访问两次内存。用了TLB之后只需要一次。
文件系统
文件系统主要负责管理和组织计算机存储设备上的文件和目录,功能包括下面的方面:
- 存储管理:将文件数据存储到物理存储介质中,并且管理空间分配,以确保每个文件都有足够的空间存储,并避免文件之间发生冲突。
- 文件管理:文件的创建、删除、移动、重命名、压缩、加密、共享等等。
- 目录管理:目录的创建、删除、移动、重命名等等。
- 文件访问控制:管理不同用户或进程对文件的访问权限,以确保用户只能访问其被授权访问的文件,以保证文件的安全性和保密性。
常见的磁盘调度算法
- 先来先服务:FCFS,按照请求到达磁盘调度器的顺序处理。但是由于没考虑到磁头移动的路径和方向,平均寻道时间较长。
- 最短寻道时间优先:SSTF,shortest seek time first,优先选择距离当前磁头最近的请求服务。
- 扫描算法:SCAN,也被称为电梯算法。磁头沿着一个方向一直扫过去,经过的磁道有请求就处理,直到另一端后,改变方向扫描回来。是一个循环的过程。
- 循环扫描:C-SCAN,circular scan,跟扫描类似,但是到达另一端后不是改变方向,而是直接回到起点重新扫描。
进程/线程之间的亲缘性
亲缘性的意思是进程/线程只在某个CPU上运行(多核心系统),这样的好处是为了防止进程/线程在CPU核心上的频繁切换,从而避免L1/L2 cache失效。
协程
协程是比线程更加轻量级的存在,不由操作系统内核管理,完全由程序控制,好处是性能有很大提升,不需要有类似线程/进程切换导致的开销。
多进程的好处?
多进程的进程之间相互隔离,一个进程崩溃不影响另一个进程。多进程的场景:Redis的主从同步,AOF和RDB过程,还有浏览器的标签页
浏览器新开的一个标签页是进程还是线程?
实际上是进程,但是浏览器会做优化,多个新打开的空白标签页会合并为一个进程。
绑核是什么?
意思是给线程指定一个核心运行,充分利用CPU的L1 L2,减少在不同核心上切换造成的cache损失。