操作系统
操作系统
操作系统是管理计算机硬件和软件资源的系统程序,它为用户和应用程序提供统一的接口和运行环境,负责处理任务调度、内存管理、文件系统、设备驱动等核心功能,使计算机系统高效、稳定、可用。
操作系统主要有哪些功能
从资源管理的角度来看,操作系统有 6 大功能:
- 进程和线程的管理:进程的创建、撤销、阻塞、唤醒,进程间的通信等。
- 存储管理:内存的分配和管理、外存(磁盘等)的分配和管理等。
- 文件管理:文件的读、写、创建及删除等。
- 设备管理:完成设备(输入输出设备和外部存储设备等)的请求或释放,以及设备启动等功能。
- 网络管理:操作系统负责管理计算机网络的使用。网络是计算机系统中连接不同计算机的方式,操作系统需要管理计算机网络的配置、连接、通信和安全等,以提供高效可靠的网络服务。
- 安全管理:用户的身份认证、访问控制、文件加密等,以防止非法用户对系统资源的访问和操作。
用户态和内核态
根据进程访问资源的特点,我们可以把进程在系统上的运行分为两个级别:
- 用户态(User Mode) : 用户态运行的进程可以直接读取用户程序的数据,拥有较低的权限。当应用程序需要执行某些需要特殊权限的操作,例如读写磁盘、网络通信等,就需要向操作系统发起系统调用请求,进入内核态。
- 内核态(Kernel Mode):内核态运行的进程几乎可以访问计算机的任何资源包括系统的内存空间、设备、驱动程序等,不受限制,拥有非常高的权限。当操作系统接收到进程的系统调用请求时,就会从用户态切换到内核态,执行相应的系统调用,并将结果返回给进程,最后再从内核态切换回用户态。
为什么要有用户态和内核态
- 在 CPU 的所有指令中,有一些指令是比较危险的比如内存分配、设置时钟、IO 处理等,如果所有的程序都能使用这些指令的话,会对系统的正常运行造成灾难性地影响。因此,我们需要限制这些危险指令只能内核态运行。这些只能由操作系统内核态执行的指令也被叫做 特权指令 。
- 如果计算机系统中只有一个内核态,那么所有程序或进程都必须共享系统资源,例如内存、CPU、硬盘等,这将导致系统资源的竞争和冲突,从而影响系统性能和效率。并且,这样也会让系统的安全性降低,毕竟所有程序或进程都具有相同的特权级别和访问权限。
因此,同时具有用户态和内核态主要是为了保证计算机系统的安全性、稳定性和性能。
用户态和内核态是如何切换的
用户态切换到内核态的 3 种方式:
- 系统调用(Trap):用户态进程 主动 要求切换到内核态的一种方式,主要是为了使用内核态才能做的事情比如读取磁盘资源。系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现。
- 中断(Interrupt):当外围设备完成用户请求的操作后,会向 CPU 发出相应的中断信号,这时 CPU 会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
- 异常(Exception):当 CPU 在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
在系统的处理上,中断和异常类似,都是通过中断向量表来找到相应的处理程序进行处理。区别在于,中断来自处理器外部,不是由任何一条专门的指令造成,而异常是执行当前指令的结果。
系统调用
系统调用是用户态程序与操作系统内核之间进行交互的接口,允许应用程序请求操作系统执行一些只有内核才能完成的受保护操作。
例如,读写文件、分配内存、创建进程、进行网络通信等操作,用户程序本身没有权限直接访问硬件或关键资源,因此必须通过系统调用让操作系统代为执行。
系统调用的过程
系统调用的过程可以简单分为以下几个步骤:
- 用户态的程序发起系统调用,因为系统调用中涉及一些特权指令(只能由操作系统内核态执行的指令),用户态程序权限不足,因此会中断执行,也就是 Trap(Trap 是一种中断)。
- 发生中断后,当前 CPU 执行的程序会中断,跳转到中断处理程序。内核程序开始执行,也就是开始处理系统调用。
- 当系统调用处理完成后,操作系统使用特权指令(如
iret
、sysret
或eret
)切换回用户态,恢复用户态的上下文,继续执行用户程序。
进程和线程
线程见Java多线程
进程:
PCB
PCB(Process Control Block) 即进程控制块,是操作系统中用来管理和跟踪进程的数据结构,每个进程都对应着一个独立的 PCB,用于记录该进程的全部关键信息。
PCB 通常包含以下内容:
- 进程标识信息:如进程 ID(PID)、父进程 ID;
- 处理器状态信息:保存 CPU 寄存器、程序计数器(PC)、程序状态字(PSW)等,用于进程切换时恢复上下文;
- 进程控制信息:如进程状态(就绪、运行、阻塞等)、优先级、调度信息;
- 内存管理信息:如页表、段表、内存分配情况;
- 文件管理信息:打开的文件列表、I/O 资源信息;
- 通信信息:用于进程间通信的缓冲区、消息队列、信号等信息。
进程有哪几种状态
- 就绪(Ready) 进程已具备运行条件,正在等待被 CPU 调度执行。
- 运行(Running) 进程正在使用 CPU 执行指令,是唯一处于执行状态的进程(在单核系统中)。
- 阻塞(Blocked)/等待(Waiting) 进程因等待某些事件(如 I/O 完成、资源可用)而暂停执行,即使有 CPU 也不能运行。
- 新建(New) 进程正在被创建,尚未进入就绪队列。
- 结束(Terminated) 进程已完成执行或被强制终止,正在释放资源。
进程间通信方式
进程间通信(IPC,Inter-Process Communication)是指不同进程之间交换数据的机制,常见的通信方式包括以下几种:
- 管道(Pipe)
- 单向通信,通常用于有亲缘关系的进程(如父子进程);
- 包括匿名管道和命名管道(FIFO)。
- 消息队列(Message Queue)
- 允许多个进程以消息的形式发送和接收数据;
- 支持异步通信,结构化、可管理。
- 共享内存(Shared Memory)
- 将一块内存区域映射到多个进程的地址空间;
- 速度快,但需要配合同步机制(如信号量)保证数据一致性。
- 信号量(Semaphore)
- 主要用于进程间的同步和互斥,不是直接用于传递数据;
- 可与其他方式联合使用,如共享内存+信号量。
- 信号(Signal)
- 一种异步通信机制,内核向进程发送中断通知,如终止信号(SIGTERM)或用户自定义信号。
- 套接字(Socket)
- 支持本地和分布式进程通信,基于网络协议;
- 常用于客户端-服务器模型,支持 TCP/UDP。
- 内存映射文件(mmap)
- 不同进程可以通过映射同一文件到内存来共享数据;
- 类似共享内存,但通常用于文件数据共享。
进程的调度算法
进程调度算法是操作系统决定哪个进程获得 CPU 执行权的策略,常见的有以下几种:
- 先来先服务(FCFS, First-Come First-Served) 最简单的调度策略,按进程到达时间先后顺序依次调度,容易导致长作业“拖延”短作业,平均等待时间较长。
- 短作业优先(SJF, Shortest Job First) 优先调度估计运行时间最短的进程,可降低平均等待时间,但无法预知准确的执行时间,可能导致长作业饥饿。
- 优先级调度(Priority Scheduling) 每个进程被分配优先级,高优先级进程优先执行。可能导致低优先级进程长期得不到调度,需引入“优先级动态调整”避免饥饿。
- 时间片轮转(RR, Round Robin) 所有就绪进程轮流执行,每个进程分配固定时间片,到时间就切换。适用于多用户系统,响应快但上下文切换频繁。
- 多级反馈队列调度(Multilevel Feedback Queue) 综合考虑优先级与时间片,引入多个队列,进程根据行为动态调整优先级,兼顾公平性与效率,是现代操作系统常用的策略。
僵尸进程和孤儿进程
僵尸进程是指一个子进程已经执行结束(即已经终止),但其父进程没有调用 wait() 或 waitpid() 回收子进程的退出状态信息,导致子进程的进程控制块(PCB)仍然保留在系统中。这种进程不会占用 CPU 和内存资源,但会占用一个 PID。如果父进程长时间不回收,系统中的僵尸进程可能堆积,耗尽 PID 资源,影响系统稳定。
孤儿进程是指一个子进程的父进程提前终止,此时孤儿进程仍在运行。为了让孤儿进程得到妥善处理,Linux 系统会自动将其由 init 进程(PID 1)接管,由 init 负责对子进程进行善后,包括资源回收等。
内存管理
内存管理是操作系统负责分配、回收和保护内存资源的一项核心功能,确保多个进程在使用内存时高效且互不干扰。
主要职责:
- 地址空间管理:为每个进程分配独立的虚拟地址空间,并映射到物理内存,保障安全隔离。
- 内存分配与回收:按需为进程分配内存,在进程结束或释放时及时回收。
- 内存保护:防止进程非法访问不属于自己的内存区域。
- 换页/置换管理:当物理内存不足时,将不活跃数据暂存到磁盘(如交换空间),实现虚拟内存扩展。
- 内存共享和重定位:支持多个进程共享公共代码段,提高效率。
内存碎片
内存碎片是指由于频繁的内存分配与释放,导致内存空间被分割成很多无法有效利用的小块区域,从而降低了内存使用效率。
根据位置不同,内存碎片分为两类:
- 外部碎片:指空闲内存被分散在不连续的区域中,虽然总空闲内存足够,但没有一块足够大的连续区域供分配。例如,有 100KB 空闲,但被分成多个 1~5KB 的小块,无法满足一个 30KB 的请求。
- 内部碎片:指实际分配给进程的内存大于其实际需要,未被使用的部分形成浪费。例如,申请 18 字节但系统按 32 字节对齐分配,剩余 14 字节就是内部碎片。
产生原因主要是由于动态内存分配机制(如 malloc/free),以及不同大小内存块频繁申请与释放,导致内存空间不再连续。
解决方式包括:
- 内存池(对象池)管理,避免频繁分配;
- 紧凑整理(如标记-整理算法);
- 使用分页或分段机制,减少对连续内存的依赖。
内存管理方式
内存管理方式是操作系统为实现高效、灵活、安全地分配和回收内存资源而采用的策略,常见的方式主要有以下几种:
- 连续分配管理 最早期的方式,将进程分配到一块连续的物理内存区域,包括静态分区和动态分区。
- 优点:简单、访问快;
- 缺点:容易产生外部碎片,不易扩展。
- 分页(Paging) 把虚拟内存和物理内存划分成固定大小的页(Page)和页框(Frame),通过页表实现地址映射。
- 优点:消除了外部碎片,支持虚拟内存;
- 缺点:可能出现内部碎片,且多级页表会增加访问开销。
- 分段(Segmentation) 将程序划分为逻辑段(如代码段、数据段、栈段等),每段可以大小不同,独立分配内存。
- 优点:更符合程序逻辑结构,利于保护和共享;
- 缺点:仍可能有外部碎片,实现比分页复杂。
- 段页式管理(Segmented Paging) 结合分页和分段的优点,每个段再分页,兼顾逻辑结构和物理管理效率,是现代操作系统常用方式。
- 优点:灵活、可扩展,支持大空间管理;
- 缺点:地址转换复杂,依赖硬件支持。
虚拟内存
虚拟内存是一种由操作系统和硬件协同提供的内存管理机制,它通过将物理内存与磁盘空间结合,使每个进程拥有一个独立、连续的逻辑内存空间,从而突破了实际物理内存的限制。
简单来说,虚拟内存让程序“以为”自己有独占的大块内存,而实际上底层由操作系统动态地将活跃的数据加载到物理内存,不活跃的数据则临时存放在磁盘(如交换区或页面文件)中。
虚拟内存的核心作用有四点:
- 扩展可用内存容量 通过将部分数据临时存放在磁盘,实现“以小博大”,让程序可以使用比实际物理内存更大的空间,支持大型应用运行。
- 实现进程隔离 每个进程拥有独立的虚拟地址空间,彼此互不干扰,提升了系统的稳定性和安全性,防止非法访问和内存泄漏影响其他进程。
- 简化内存管理 进程看到的是连续的虚拟内存,程序员不必关心物理内存碎片和实际分布,提高编程效率,也便于操作系统动态分配内存。
- 支持内存保护与共享 操作系统可以控制哪些虚拟页可读/可写/可执行,还可实现只读共享(如多个进程共享同一个库文件的代码段),减少资源浪费。
虚拟地址和物理地址
虚拟地址是进程在访问内存时使用的地址,是一种逻辑上的地址; 物理地址是实际存在于硬件内存条上的地址,用于真正读写内存数据。
操作系统为每个进程分配独立的虚拟地址空间,进程只能访问自己的虚拟地址,无法直接看到或访问物理内存。
为了让多个进程共享物理内存且互不干扰,操作系统和硬件引入了地址映射机制,即将虚拟地址映射到物理地址。
这个映射过程由**内存管理单元(MMU)**和操作系统联合完成,通常依赖分页机制实现:
- 虚拟地址被划分为页(Page),物理内存划分为页框(Frame);
- 每个进程维护一个页表,记录每个虚拟页对应的物理页框;
- 当进程访问某个虚拟地址时,MMU 通过页表找到对应的物理地址;
- 如果该页还没被加载到物理内存,就触发缺页中断,由操作系统从磁盘加载页面,再更新页表完成映射。
这样设计的意义在于:
- 允许多个进程共享同一套虚拟地址范围,实现地址空间隔离;
- 提高内存安全性和灵活性;
- 便于操作系统对内存进行统一调度和管理。
虚拟地址空间是操作系统为每个进程提供的一套逻辑地址范围,进程只能访问自己的虚拟空间,不直接接触物理内存; 物理地址空间是真实存在于内存硬件上的地址范围,用于存储实际的数据和程序。
分段机制、分页机制、段页机制
文件系统
文件系统主要负责管理和组织计算机存储设备上的文件和目录。
功能
- 存储管理:将文件数据存储到物理存储介质中,并且管理空间分配,以确保每个文件都有足够的空间存储,并避免文件之间发生冲突。
- 文件管理:文件的创建、删除、移动、重命名、压缩、加密、共享等等。
- 目录管理:目录的创建、删除、移动、重命名等等。
- 文件访问控制:管理不同用户或进程对文件的访问权限,以确保用户只能访问其被授权访问的文件,以保证文件的安全性和保密性。
提高文件系统性能的方式
- 优化硬件:使用高速硬件设备(如 SSD、NVMe)替代传统的机械硬盘,使用 RAID(Redundant Array of Inexpensive Disks)等技术提高磁盘性能。
- 选择合适的文件系统选型:不同的文件系统具有不同的特性,对于不同的应用场景选择合适的文件系统可以提高系统性能。
- 运用缓存:访问磁盘的效率比较低,可以运用缓存来减少磁盘的访问次数。不过,需要注意缓存命中率,缓存命中率过低的话,效果太差。
- 避免磁盘过度使用:注意磁盘的使用率,避免将磁盘用满,尽量留一些剩余空间,以免对文件系统的性能产生负面影响。
- 对磁盘进行合理的分区:合理的磁盘分区方案,能够使文件系统在不同的区域存储文件,从而减少文件碎片,提高文件读写性能。
常见的磁盘调度算法
先来先服务(FCFS, First-Come First-Served) 按照请求到达的顺序依次处理,简单但可能导致大量磁头移动,效率较低。
最短寻道时间优先(SSTF, Shortest Seek Time First) 优先处理距离当前磁头位置最近的请求,减少总磁头移动距离,但可能导致远处请求长时间得不到处理(“饥饿”)。
扫描算法(SCAN,也称电梯算法) 磁头按一个方向移动,处理沿途请求,直到边界后再反向移动处理另一方向的请求,类似电梯运行。
循环扫描算法(C-SCAN) 磁头只向一个方向处理请求,到达边界后直接返回起始端重新开始扫描,避免中间区域请求过度集中处理。
LOOK 和 C-LOOK 算法 是对 SCAN 和 C-SCAN 的优化:磁头只扫描到最后一个请求的位置而不是固定边界,减少不必要移动。
硬链接和软连接
在 Linux 系统中,硬链接和软连接是两种常见的文件引用方式,用于实现多个路径指向同一个文件或资源。它们的本质区别在于链接的对象不同:硬链接是链接到文件本身的 inode 节点,而软连接是链接到文件路径。
硬链接本质上是为同一个文件创建了一个新的名字,两个文件名共享同一个 inode 和数据块。当其中一个被删除时,文件内容并不会立即消失,只有当所有硬链接都删除后,系统才会真正释放文件的磁盘空间。不过硬链接不能跨文件系统,也不能对目录创建硬链接(为防止循环结构)。
软连接也叫符号链接,是一个特殊的文件,它的内容是指向另一个文件路径的字符串。它更像是一个快捷方式,可以跨文件系统,也可以链接目录。缺点是如果目标文件被删除,软链接就会变成“悬挂”状态,无法使用。
硬链接为什么不能跨文件系统
硬链接是通过 inode 节点号建立连接的,而硬链接和源文件共享相同的 inode 节点号。
然而,每个文件系统都有自己的独立 inode 表,且每个 inode 表只维护该文件系统内的 inode。如果在不同的文件系统之间创建硬链接,可能会导致 inode 节点号冲突的问题,即目标文件的 inode 节点号已经在该文件系统中被使用。