进程、进程、内存、调度总结

一、进程

定义

进程 (Process)是操作系统进行资源分配和调度的基本单位,简单来说,它是 "正在运行的程序的实例"。

我们编写的代码只是一个存储在硬盘的静态文件,通过编译后就会生成二进制可执行文件,当我们运行这个可执行文件后,它会被装载到内存中,接着 CPU 会执行程序中的每一条指令,那么这个运行中的程序,就被称为「进程」。

状态

【创建,就绪,运行,阻塞,结束】(内存),【就绪挂起,阻塞挂起】(外存/硬盘)

程序控制块 PCB

在操作系统中,是用进程控制块(process control block,PCB)数据结构来描述进程的。

PCB(Process Control Block,进程控制块)是操作系统内核中管理进程的核心数据结构,每个进程在内存中都对应一个PCB,它记录了进程的所有关键信息,是操作系统识别、调度、控制进程的"唯一依据"。

PCB的具体内容因操作系统而异(如Linux、Windows的实现细节不同),但核心包含以下几类信息:

1. 进程标识信息(唯一标识进程)

用于区分不同进程,是进程的"身份证":

  • 进程ID(PID) :系统为进程分配的唯一整数编号(如Linux中ps命令查看的PID),用于标识进程。
  • 父进程ID(PPID) :创建当前进程的父进程的PID(如shell进程启动lsls的PPID是shell的PID)。
  • 用户ID(UID)/组ID(GID):记录进程所属的用户和用户组,用于权限控制(如判断进程是否有权限访问某文件)。
2. 进程状态信息(描述进程当前状态)

记录进程的生命周期状态,是调度的核心依据:

  • 当前状态:进程处于的状态(如运行态、就绪态、阻塞态、终止态等)。
  • 等待原因:若进程处于阻塞态,记录其等待的事件(如等待磁盘I/O完成、等待信号量)。
3. 调度信息(用于进程调度)

供操作系统调度器决定"何时让该进程占用CPU":

  • 优先级:进程的调度优先级(数值越高优先级越高,或反之),高优先级进程更可能被优先调度。
  • 时间片信息:已使用的CPU时间、剩余的时间片(如RR调度算法中,时间片用完后进程会被暂停)。
  • 调度队列指针:指向进程所在的调度队列(如就绪队列、阻塞队列)的下一个/上一个PCB,用于将PCB组织成链表(方便调度器遍历)。
4. 资源信息(记录进程占用的资源)

描述进程使用的系统资源,用于资源回收和管理:

  • 内存信息:进程虚拟地址空间的范围(如代码段、数据段、堆、栈的起始和结束地址)、页表指针(指向该进程的页表,用于虚拟地址到物理地址的映射)。
  • 打开文件列表:进程打开的文件描述符集合(如打开的文本文件、网络套接字),每个描述符对应内核中的文件结构体。
  • I/O设备:进程占用的I/O设备(如打印机、显卡)的标识信息。
  • 信号量/锁:进程持有的同步资源(如已获取的互斥锁),用于避免资源竞争。
5. 上下文信息(进程的运行环境)

记录进程被暂停时的CPU状态,用于"恢复运行":

当进程被切换(如时间片用完、被高优先级进程抢占)时,操作系统会将当前CPU的状态保存到PCB,后续恢复运行时再从PCB加载这些状态,让进程"无缝继续执行"。具体包括:

  • 寄存器值:通用寄存器、累加器、基址寄存器等的值(这些寄存器存储了进程运行时的中间数据)。
  • 程序计数器(PC):记录进程被暂停时,下一条要执行的指令的地址(恢复时从该地址继续执行)。
  • 栈指针(SP):指向进程用户栈或内核栈的当前位置(记录函数调用的上下文)。
总结

PCB是进程的"全景档案",包含了**"我是谁(标识)""我状态如何(状态)""我该何时运行(调度)""我用了什么资源(资源)""我暂停在哪(上下文)"** 五大类信息。操作系统通过管理PCB,实现对进程的创建、调度、终止、资源回收等全生命周期控制------可以说,"操作系统管理进程,本质是管理PCB"。

进程的上下文

进程是由内核管理和调度的,所以进程的切换只能发生在内核态。

进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源。

通常,会把交换的信息保存在进程的 PCB,当要运行另外一个进程的时候,我们需要从这个进程的 PCB 取出上下文,然后恢复到 CPU 中,这使得这个进程可以继续执行

进程与程序的区别

程序:是静态的指令集合(如存放在硬盘上的浏览器.exe),不占用系统资源,仅作为文件存在。

进程:是动态的执行过程,由程序、数据和操作系统为其分配的资源(如内存空间、CPU 上下文)组成,会随着程序的运行而创建、运行、暂停或终止。

例如:双击 "浏览器.exe"(程序),操作系统会加载其代码到内存,分配 CPU 时间和网络资源,此时就产生了一个 "浏览器进程"(动态执行的实例)。

二、线程

定义:

线程 (Thread)是进程内的最小执行单元,也是操作系统进行 CPU 调度的基本单位。

一个进程可以包含多个线程,同一个进程内多个线程之间可以共享代码段、数据段、打开的文件等资源,但每个线程都有独立一套的寄存器和栈,这样可以确保线程的控制流是相对独立的。

例如:打开 "微信"(一个进程),它至少有一个主线程负责界面显示;同时可能有 "消息接收线程""文件传输线程" 等子线程,这些线程都属于微信进程,共享微信的内存资源(如聊天记录缓存)。

线程的实现方式

用户线程(User Thread) :在用户空间实现的线程,不是由内核管理的线程,是由用户态的线程库来完成线程的管理;
内核线程(Kernel Thread) :在内核中实现的线程,是由内核管理的线程;
轻量级进程(LightWeight Process):在内核中来支持用户线程;

线程和进程的区别:

1. 线程是进程的 "子集",依赖进程存在

一个进程至少包含一个线程(称为 "主线程"),也可以创建多个线程("子线程");

线程不能独立存在,必须依附于进程 ------ 进程一旦终止,其内部的所有线程都会被强制销毁。
2. 线程共享进程的资源,进程间资源隔离

线程间共享:同一进程内的所有线程共享该进程的内存空间、文件句柄、网络连接等资源。例如:一个进程的多个线程可以直接访问同一块内存中的变量,无需额外通信机制。

进程间隔离:不同进程拥有独立的内存空间,资源互不干扰(除非通过 "进程间通信" 机制,如管道、共享内存等主动交互)。例如:微信进程和浏览器进程的内存是完全隔离的,微信无法直接读取浏览器的缓存。
3. 线程是 CPU 调度的单位,进程是资源分配的单位

操作系统的 CPU 调度直接面向线程:CPU 会在多个线程间快速切换(如每秒切换数百次),让多个线程 "宏观上同时运行"(并发)。

进程是资源分配的最小单位:操作系统为每个进程分配独立的内存、文件描述符等资源,而线程不单独分配资源(依赖进程的资源池)。
4. 线程切换成本远低于进程切换

进程切换时,操作系统需要保存整个进程的资源状态(如内存页表、打开的文件等),切换成本高;

线程切换时,只需保存线程的局部数据(如寄存器状态、程序计数器),因共享进程资源,无需切换资源上下文,成本极低。

三、内存

虚拟内存,物理内存,页表,缓存的关系


虚拟内存:

虚拟内存是一种计算机内存管理技术,它允许程序使用比实际物理内存(RAM)更大的地址空间。它的基本原理是 将暂时不使用的内存页存储到磁盘(如交换空间)中,当程序需要访问这些数据时,再将它们加载回物理内存。

虚拟内存的基本思想是每个程序拥有属于自己的地址空间,虚拟内存被划分成若干个页(Page),而物理内存被划分为若干个页框(Page Frame),每个页框的大小与页面大小相同。

页表:

虚拟内存通过页表将虚拟地址映射到物理地址。页表本质上是存储在内存中的一张映射表,记录了每个虚拟页 对应的物理页框地址。当程序访问虚拟地址时,内存管理单元(MMU)会通过查找页表完成地址转换。

页表使用虚拟地址的页号作为索引,以找到实际物理存储器中的页号。每个程序都有一张自己的页表

页表的存储位置在内存中 ,但为了提高访问效率,现代处理器通常会使TLB(Translation Lookaside Buffer) 作为页表缓存。TLB位于CPU中,用于存储最近访问的页表项,从而减少频繁访问内存带来的性能开销。

在多级页表机制下,页表被分为多个层级(如二级或四级页表),每一级页表的内容也存储在内存中。只有在需要时,操作系统才会加载相关页表项到内存中,这种机制有效节约了内存空间。

当页表项在内存中未找到时,会触发缺页异常,操作系统会分配物理内存并更新页表。通过这种方式,页表的动态维护始终依赖内存。

用户空间,内核空间

操作系统会把虚拟地址空间 划分为两部分,一部分为内核空间,另一部分为用户空间

进程在内存中的分布

以32位系统为例,共有4G的寻址能力,进程在内存中的分布如下图所示。Linux默认将高地址的1G空间分配给内核,称为内核空间,剩下的3G空间分配给进程使用,称为用户空间。

四、用户态,内核态

简单来说内核态就是操作系统运行线程,用户态就是线程执行用户自己的程序。

用户态

不能直接使用系统资源,也不能改变 CPU 的工作状态,并且只能访问这个用户程序自己的存储空间

内核态

  • 系统中既有操作系统的程序,也有普通用户程序。为了安全性和稳定性,操作系统的程序不能随便访问,这就是内核态。即需要执行操作系统的程序就必须转换到内核态才能执行
  • 内核态可以使用计算机所有的硬件资源

用户态到内核态切换

  1. 系统调用:用户态进程主动切换到内核态的方式,用户态进程通过系统调用向操作系统申请资源完成工作,例如 fork()就是一个创建新进程的系统调用,系统调用的机制核心使用了操作系统为用户特别开放的一个中断来实现,如Linux 的 int 80h 中断,也可以称为软中断
  2. 异常:当 C P U 在执行用户态的进程时,发生了一些没有预知的异常,这时当前运行进程会切换到处理此异常的内核相关进程中,也就是切换到了内核态,如缺页异常
  3. 中断:当 C P U 在执行用户态的进程时,外围设备完成用户请求的操作后,会向 C P U 发出相应的中断信号,这时 C P U 会暂停执行下一条即将要执行的指令,转到与中断信号对应的处理程序去执行,也就是切换到了内核态。如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后边的操作等。

五、调度

什么是调度

操作系统的调度(Scheduling) 是指操作系统按一定规则为进程/线程分配CPU资源的过程 。由于CPU是计算机中最核心的硬件资源(同一时刻一个CPU核心只能运行一个线程),而系统中通常有多个进程/线程需要运行,调度的核心目标是高效、公平地分配CPU时间,以提升系统吞吐量(单位时间完成的任务数)、缩短响应时间(用户操作到反馈的时间)、保证公平性(避免某进程长期占用CPU)等。

调度发生的时机

调度本质是"CPU使用权的切换",当CPU的当前使用者"不再适合继续占用CPU"时,就会触发调度。常见触发场景包括:

  1. 进程/线程状态转换时

    • 运行态→阻塞态:进程因等待外部事件(如I/O请求、sleep)主动放弃CPU,此时需调度其他就绪进程运行(例如:进程调用read()读取文件,进入阻塞态,CPU空闲,触发调度)。
    • 阻塞态→就绪态:进程等待的事件完成(如I/O数据到达),进入就绪队列,可能触发调度(若当前运行进程优先级较低,新就绪进程优先级更高,则抢占CPU)。
  2. 时间片用完时

    现代系统多采用"时间片轮转"机制,为每个就绪进程分配固定的CPU时间片(如10ms)。当时间片耗尽,当前进程被强制暂停,进入就绪队列,触发调度(例如:浏览器渲染线程的时间片用完,切换到网络线程运行)。

  3. 进程/线程终止或退出时

    进程完成任务后终止(如程序执行完main函数),CPU变为空闲,需从就绪队列中调度新进程(例如:命令行执行ls命令完成后,ls进程终止,shell进程重新获得CPU)。

  4. 优先级变化时

    若高优先级进程进入就绪队列,操作系统可能"抢占"当前低优先级进程的CPU,触发调度(例如:实时监控进程检测到异常,优先级临时提升,抢占普通应用的CPU)。

  5. 系统调用或中断处理结束后

    进程从内核态返回用户态前,操作系统会检查是否需要调度(例如:系统调用完成后,发现有更高优先级的就绪进程,则切换调度)。

常见的调度算法

调度算法的设计需根据系统场景(如批处理、交互式、实时系统)权衡目标(吞吐量、响应时间、公平性等),常见算法包括:

1. 先来先服务(FCFS,First-Come First-Served)
  • 原理:按进程到达就绪队列的顺序分配CPU,先到的先运行,直到进程完成或阻塞。
  • 优点:简单公平,无饥饿(每个进程最终都会被调度)。
  • 缺点:对短作业不友好(长作业会阻塞短作业,导致平均响应时间变长)。
  • 场景:早期批处理系统,适合长任务为主的场景。
2. 短作业优先(SJF,Shortest Job First)
  • 原理:优先调度"预计运行时间最短"的就绪进程。
  • 优点:能显著缩短平均等待时间和平均响应时间,提升吞吐量。
  • 缺点
    • 需预知进程的运行时间(实际中难精确获取);
    • 可能导致长作业"饥饿"(长期得不到调度)。
  • 场景:批处理系统,适合任务运行时间可预估的场景(如后台计算任务)。
3. 时间片轮转(RR,Round-Robin)
  • 原理:为每个就绪进程分配固定时间片(如5-100ms),进程用完时间片后被暂停,放回就绪队列末尾,轮到下一个进程运行。
  • 优点:响应时间短,适合交互式系统(如桌面应用),每个进程都能得到公平的CPU时间。
  • 缺点:时间片过短会增加调度切换开销(上下文切换耗时);过长则退化为FCFS。
  • 场景:交互式系统(如Windows、Linux的用户态进程调度)。
4. 优先级调度(Priority Scheduling)
  • 原理:为每个进程分配优先级(数字越小优先级越高,或反之),每次从就绪队列中选择优先级最高的进程调度。
  • 优点:可按任务重要性分配资源(如实时任务优先级高于普通任务)。
  • 缺点:低优先级进程可能"饥饿"(永远抢不过高优先级进程)。
  • 改进:"优先级老化"机制(低优先级进程等待时间越长,优先级自动提升)。
  • 场景:多任务混合系统(如同时运行实时监控和普通应用的服务器)。
5. 多级反馈队列(Multilevel Feedback Queue)
  • 原理 :设置多个优先级不同的就绪队列,高优先级队列时间片短(如10ms),低优先级队列时间片长(如100ms)。
    • 新进程进入最高优先级队列,用完时间片后若未完成,降级到下一级队列;
    • 高优先级队列空时,才调度低优先级队列的进程。
  • 优点:兼顾短作业(在高优先级队列快速完成)、长作业(在低优先级队列用长时片运行)和交互式任务(高优先级响应快),是综合性能最优的算法之一。
  • 场景:通用操作系统(如Linux、Unix的调度器早期版本)。
6. 实时调度(Real-Time Scheduling)
  • 原理 :针对实时系统(如工业控制、自动驾驶),要求任务在"截止时间"前必须完成,分为:
    • 硬实时:截止时间必须满足(如导弹制导,超时即失效);
    • 软实时:尽量满足截止时间(如视频播放,偶尔卡顿可接受)。
  • 常见算法
    • 最早截止时间优先(EDF):优先调度截止时间最早的任务;
    • 速率单调调度(RMS):周期越短的任务优先级越高(适用于周期性实时任务)。
总结

操作系统调度的核心是"CPU资源的合理分配",触发时机与进程状态变化、时间片、优先级等相关。不同调度算法适用于不同场景:

  • FCFS简单公平
  • SJF适合短任务
  • RR适合交互场景
  • 多级反馈队列兼顾多种需求
  • 实时调度则保障时间敏感任务

实际系统(如Linux)通常采用混合算法(如CFS完全公平调度器,基于优先级和时间片的动态调整),平衡效率与公平性。

六、参考

小林coding
用户态,内核态
深入解析虚拟内存:页表、地址转换与 TLB 加速机制

相关推荐
努力学习的小廉2 小时前
深入了解linux网络—— TCP网络通信(上)
linux·网络·tcp/ip
青草地溪水旁3 小时前
socketpair深度解析:Linux中的“对讲机“创建器
linux·服务器·socket编程
想唱rap3 小时前
Linux指令(1)
linux·运维·服务器·笔记·新浪微博
woshihonghonga3 小时前
Ubuntu20.04下的Pytorch2.7.1安装
linux·人工智能·ubuntu
字节高级特工3 小时前
网络协议分层与Socket编程详解
linux·服务器·开发语言·网络·c++·人工智能·php
minji...5 小时前
Linux 权限的概念及shell命令运行原理
linux·运维·服务器
欢鸽儿5 小时前
理解Vivado的IP综合策略:“Out-of-Context Module Runs
linux·ubuntu·fpga
HappyGame026 小时前
Linux多线程编程
linux
躺着数星星6 小时前
Linux中安装es
linux·elasticsearch·jenkins