linux中的进程

进程是什么

1. 进程

进程(Process) 是操作系统中对程序一次运行过程 的抽象描述,是操作系统进行资源分配 和CPU 调度的基本单位。

从本质上讲,进程不是程序本身,也不是单纯的内存空间,而是:

程序在操作系统管理下的一次动态执行实体

其"动态性"体现在:

  • 有明确的生命周期(创建、运行、阻塞、结束)

  • 有不断变化的执行状态

  • 会被操作系统调度、挂起、唤醒和回收

因此,进程是操作系统为了管理并发执行而引入的一种抽象对象。


2. 进程的本质:进程 = 内部数据结构 + 程序代码与数据

结论性表述

从操作系统(尤其是内核)的视角看,可以将进程概括为:

**进程 = 内核中的进程描述数据结构

  • 该进程所运行的程序代码与数据**

这一定义同时涵盖了:

  • 操作系统如何"认识"进程

  • 进程实际"执行"的内容


为什么必须有"内部数据结构"?

操作系统需要对进程进行管理,而管理的前提是:

进程必须是"可描述、可定位、可操作"的对象

为此,操作系统为每个进程维护一组内部数据结构,用于记录和管理该进程的运行环境,例如:

  • 进程的唯一标识(PID)

  • 当前执行状态(运行、就绪、阻塞等)

  • CPU 上下文信息(用于切换)

  • 内存使用情况

  • 打开的文件和其他系统资源

  • 与其他进程的父子关系

这些信息并不属于程序本身,而是操作系统为了管理进程而额外维护的状态。

👉 没有这些内部数据结构,操作系统就无法调度、暂停、恢复或终止一个进程。

因此,从内核视角看:内部数据结构是"进程存在的前提"


为什么还必须有"程序代码与数据"?

另一方面,如果只有内部数据结构,而没有程序代码与数据:进程将"无事可做",不具备任何计算意义

进程所运行的程序代码与数据包括:可执行程序的指令(代码段),程序使用的全局数据、堆、栈,运行时依赖的共享库

这些内容决定了:进程"要做什么",进程"如何计算"

👉 程序代码与数据赋予进程"行为和功能"。


二者的分工与关系

可以从职责上区分这两部分:

组成部分 作用
内部数据结构 操作系统管理进程的依据(调度、资源、状态)
程序代码与数据 进程实际执行的计算内容

二者缺一不可:

  • 只有程序代码,没有内部数据结构 → 程序无法运行

  • 只有内部数据结构,没有程序代码 → 进程没有意义

因此:

进程并不是"程序"
而是"被操作系统管理并正在执行的程序实例"


推论

由"进程 = 内部数据结构 + 程序代码与数据"可以自然推出:

  1. 同一程序可以对应多个进程

    • 代码可以共享

    • 内部数据结构彼此独立

  2. 进程是操作系统的管理对象,而程序不是

    • 操作系统"看见"的是进程

    • 程序只是进程运行的内容之一

  3. 线程本质上是共享代码与数据、但拥有独立执行状态的执行实体

    为后续理解"线程为何被视为轻量级进程"奠定基础


好,这一节正好是**"进程概念 → 内核设计方法论"** 的桥梁。我按你写笔记的方式来,先给结论,再回答「为什么」,最后解释「怎么样」,逻辑是可递进、可展开的。


为什么以及怎么样:先描述,后组织

1 结论性说明

Linux 对进程的管理遵循一个非常核心的设计思想:

先对进程进行完整、统一的描述,
再根据不同的管理需求对这些描述对象进行组织。

也可以概括为:

描述是基础,组织是手段;
描述面向"进程是什么",组织面向"如何管理进程"。


2 为什么要"先描述,后组织"?

操作系统首先需要"认识进程"

操作系统要管理进程,必须先回答一个最基本的问题:

"一个进程在系统中到底由哪些信息构成?"

如果没有统一的描述:无法判断两个进程是否是不同实体,无法保存和恢复进程状态,无法在调度、信号、内存管理等子系统之间共享信息

在操作系统中管理进程之前,内核首先必须解决一个根本问题:进程在内核中到底以什么形式存在。进程并不是一个抽象的概念标签,而是一个需要被保存、被查找、被调度、被切换的实体。为了做到这一点,内核必须为每一个进程建立一个稳定且完整的"描述",用以记录该进程当前所处的状态、所占用的资源以及与系统中其他进程的关系。只有当进程被明确地描述出来,它才可能成为操作系统内部一个可以被操作和管理的对象。

因此,内核必须为每个进程建立一个完整、统一的描述,作为所有管理行为的基础。

👉 描述的本质:定义"进程是什么"


不同管理需求需要不同的"视角"

进程需要被管理的方面是多样的:

  • 调度器关心:哪些进程可以运行?

  • 信号子系统关心:信号该发给谁?

  • 进程控制关心:父子关系如何维护?

  • 用户态工具关心:系统中有哪些进程?

这些问题:关注点不同,使用场景不同,数据访问方式也不同

如果把所有管理逻辑都混进一个"统一结构",会导致:结构臃肿,子系统强耦合,扩展和维护困难

👉 因此,"描述"和"如何使用描述"必须分离


先描述,才能被多次、灵活地组织

一旦每个进程都有了稳定的描述对象:

  • 同一个进程

    → 可以同时参与多种管理结构

  • 不同的子系统

    → 可以用各自最合适的数据结构来管理进程

这种"先描述"的做法,本质上是为了让进程在内核中具有明确而统一的存在形式。无论是调度器、内存管理、信号处理,还是进程控制与回收,所有子系统在面对同一个进程时,都必须基于同一份事实来源。如果没有一个统一的描述,各个子系统就不得不维护各自的进程信息副本,这不仅会造成信息冗余,还会引入一致性和同步上的复杂问题。因此,内核通过集中式的进程描述,将"进程是什么"这一问题先行固定下来。

这使得内核可以做到:

"一个进程,多种组织方式,多种管理视角"


3 "描述"和"组织"各自解决什么问题?

描述解决的问题

描述关注的是单个进程自身的完整性:

  • 进程是谁(身份)

  • 在做什么(状态)

  • 用了什么资源(内存、文件)

  • 当前执行到哪里(上下文)

在完成对单个进程的描述之后,内核才进一步考虑如何同时管理大量进程。系统中往往存在成百上千个进程,不同的管理任务对进程的"关注方式"并不相同。有的场景需要根据进程标识快速定位某一个进程,有的场景需要遍历系统中所有进程,有的场景只关心当前可运行的进程集合,还有的场景需要维护进程之间的父子层级关系。这些需求在访问模式、效率要求和结构形式上都存在明显差异,因此不适合用单一的数据结构来统一解决。

👉 描述的目标是:
让一个进程在内核中成为一个"自洽、独立、可保存"的对象


组织解决的问题

组织关注的是进程之间的关系和管理效率:

  • 如何快速找到某个进程

  • 如何遍历所有进程

  • 如何选择下一个运行的进程

  • 如何表达进程之间的层级关系

在这一背景下,"后组织"的思想自然产生。内核并不重新定义新的进程对象,而是以已经存在的进程描述为基础,根据不同的管理目的,将这些描述对象组织进不同的数据结构中。这些组织结构并不包含进程的完整信息,而只是保存对进程描述的引用或链接,从而以最低的成本服务于各自的管理需求。同一个进程描述可以同时出现在多种组织结构中,而这些组织方式彼此独立、互不干扰。

👉 组织的目标是:
让大量进程在系统中"可管理、可扩展、高性能"


4 怎么样做到"先描述,后组织"?

每个进程对应一个独立的描述对象

Linux 中的基本做法是:

  • 每创建一个进程

  • 就分配一个独立的进程描述对象

  • 该对象完整记录该进程的所有关键信息

这个描述对象:

  • 生命周期与进程一致

  • 不依附于某一种管理方式

  • 可以被多个子系统同时引用

Linux 在实现"先描述,后组织"这一思想时,核心做法是将进程本身的定义 与进程的管理方式严格分离。内核在创建进程时,首先为其分配并初始化一个专门用于描述进程的内部对象,该对象完整记录进程的身份、状态、执行上下文以及所占用的系统资源。这一描述对象在进程生命周期内保持唯一性和权威性,内核中所有关于该进程的操作都以它为事实基础,而不会再生成其他等价的进程副本。

👉 这是"先描述"的具体体现


通过"引用"而不是"复制"来组织进程

在此基础上,内核采用的组织方式是:

用不同的数据结构保存对进程描述对象的引用

而不是:

  • 为调度复制一份

  • 为父子关系再建一份

  • 为 PID 管理再建一份

这样做的结果是:

  • 进程信息只有一份真实来源

  • 各种组织结构只关心"如何使用它"

在此基础上,内核并不把管理逻辑直接写死在进程描述之中,而是通过引用和链接的方式,将同一个进程描述对象纳入不同的管理结构。每一种管理需求------例如查找、调度、层级关系维护或资源控制------都有各自合适的数据结构,而这些结构中保存的并不是进程的完整信息,而是指向进程描述对象的关联关系。这样一来,组织结构只负责"如何使用进程",而不负责"进程是什么"。

进程描述在设计时具有高度的稳定性和完整性。它对外暴露的并不是某一种特定用途的视角,而是能够被多个子系统同时理解和使用的通用信息集合。调度器、内存管理子系统和信号子系统虽然关注点不同,但它们都可以基于同一个进程描述读取或更新自己关心的部分,而无需关心该进程在其他管理结构中的存在方式。

👉 这是"后组织"的关键手段


不同组织结构服务于不同目的

同一个进程描述对象,可以同时:

  • 被放入"按 ID 快速查找"的结构中

  • 被挂入"进程层级关系"的结构中

  • 在"调度相关结构"中等待运行

  • 参与资源控制、命名空间等管理结构

这些组织方式之间:

  • 相互独立

  • 互不干扰

  • 但操作的都是同一个进程描述

当进程状态发生变化时,内核通过维护这些组织结构与进程描述之间的一致性来完成管理。例如,一个进程从不可运行状态转为可运行状态时,其描述对象本身并不会改变身份,而只是被相应地加入或移出某些管理结构。进程的"存在"始终由描述对象保证,而进程的"可管理性"则由组织结构动态体现。这使得进程的本质信息与管理策略在实现层面自然分离。

最终,Linux 通过这种方式实现了"一个进程描述,多种组织方式"的结构:进程先以描述对象的形式存在于内核中,再根据需要被挂接到不同的管理体系中。描述决定进程的身份与状态,组织决定进程在系统中的管理路径和处理方式。


5 抽象层面的类比

可以这样理解:

描述进程,类似于定义一个"人"的完整档案

组织进程,则是把这些人:

  • 按家庭关系分组

  • 按部门分组

  • 按权限分组

  • 按当前是否在岗排队

档案只有一份,但组织方式可以有很多种


6 小结

Linux 对进程的管理遵循"先描述,后组织"的思想。

先通过统一的描述对象,完整刻画单个进程的状态和资源;

再根据调度、查找、层级关系等不同需求,

将这些描述对象组织进不同的数据结构中。

这种设计使得进程描述稳定、管理方式灵活,

也是 Linux 内核可扩展、高性能的重要原因之一。


认识pcb(Process Control Block,进程控制块)

PCB 里保存了:进程是谁、现在跑到哪了、用什么资源、该怎么调度、和谁有关系。


PCB 里通常包含哪些内容?

PCB(Process Control Block,进程控制块)是操作系统内核用于描述和管理进程的核心数据结构。在 Linux 系统中,PCB 主要由 task_struct 结构体实现。内核并不直接操作"进程"这一抽象概念,而是通过 PCB 来感知进程的存在、状态以及所占用的系统资源,因此可以认为 PCB 是进程在内核中的唯一表示。

1、进程的"身份信息"

PCB 中首先包含进程的基本标识信息,用于唯一确定一个进程及其权限属性。这些信息包括进程 ID、父进程 ID、所属用户和用户组等。通过这些字段,内核能够区分不同进程,并进行权限检查和进程层级管理。


2、进程状态(非常重要)

PCB 还记录了进程的当前状态,用以描述进程在生命周期中所处的阶段。常见的状态包括运行态、就绪态、睡眠态、停止态以及僵尸态。进程状态是进程调度和状态转换的依据,系统工具如 ps 和 top 所显示的进程状态信息,正是来源于 PCB 中的状态字段。

常见状态包括:

  • TASK_RUNNING:正在运行 / 就绪

  • TASK_INTERRUPTIBLE:可中断睡眠

  • TASK_UNINTERRUPTIBLE:不可中断睡眠(如 IO)

  • TASK_STOPPED:被暂停

  • TASK_ZOMBIE:僵尸进程

📌 ps, top 看到的状态,就来自 PCB。


3、CPU 相关信息(上下文)

为了支持进程的切换与恢复,PCB 中保存了与 CPU 执行相关的上下文信息。这些内容包括程序计数器、栈指针以及通用寄存器的值。当发生进程切换时,内核会将当前进程的 CPU 上下文保存到其 PCB 中,同时从下一个进程的 PCB 中恢复对应的上下文,从而实现进程在时间上的并发执行。

这部分决定了进程切换是否可行:

  • 各种 寄存器的值

    • PC(程序计数器)

    • SP(栈指针)

    • 通用寄存器

  • 内核栈指针

  • 用户栈指针

🔁 进程切换 = 保存旧进程 PCB + 恢复新进程 PCB


4、调度信息

在进程调度方面,PCB 中还包含调度策略和优先级等信息。调度器根据 PCB 中的调度参数决定进程何时获得 CPU 以及能够运行多长时间。Linux 的进程调度机制正是围绕 PCB 中的调度相关字段进行工作的。

  • 调度策略:

    • SCHED_NORMAL

    • SCHED_FIFO

    • SCHED_RR

  • 优先级(priority / nice 值)

  • 时间片信息

  • 调度队列指针

💡 Linux 调度器(CFS)就是围绕 PCB 工作的。


5、内存管理信息

PCB 还维护了进程的内存管理信息,用于描述进程所拥有的虚拟地址空间。通过指向内存描述结构体的指针,PCB 与进程的代码段、数据段、堆和栈等内存区域建立联系。进程创建时,内核会为其建立相应的内存管理结构,并在进程运行期间通过 PCB 进行统一管理。

  • 指向 mm_struct

  • 虚拟地址空间:

    • 代码段

    • 数据段

    • 堆

    • 栈

  • 页表信息

📌 fork() 后父子进程的 PCB 会复制 + 写时拷贝(COW)。


6、文件和 IO 相关

在文件与输入输出管理方面,PCB 中保存了进程已打开的文件信息以及文件系统相关的上下文。进程在运行过程中打开的文件描述符表、当前工作目录等内容,都可以通过 PCB 间接访问,这使得操作系统能够正确地进行文件访问控制和资源回收。

  • 打开的文件描述符表(fd table)

  • 当前工作目录(cwd)

  • 根目录(root)

  • 文件系统上下文

比如你写:

复制代码
int fd = open("a.txt", O_RDONLY);

👉 fd 就被记录在 PCB 关联的数据结构里。


7、进程关系(组织结构)

此外,PCB 还记录了进程之间的组织关系。每个进程在 PCB 中都保存了指向父进程和子进程的引用,从而在内核中形成一棵进程树。这种结构为进程的创建、终止以及作业控制提供了基础支持。

  • 父进程

  • 子进程链表

  • 兄弟进程

  • 进程组 ID

  • 会话 ID

📌 shell、后台进程、作业控制都靠这套关系。


8、信号相关

在信号处理方面,PCB 中包含了与信号相关的数据,用于描述进程能够接收哪些信号、当前是否存在未处理的信号以及对应的处理方式。信号机制正是通过修改和检查 PCB 中的相关字段来实现对进程的异步控制。

  • 信号掩码(blocked signals)

  • 待处理信号集合

  • 信号处理函数表

kill -9 背后就是往 PCB 里塞信号。

注:信号就是操作系统给进程发的紧急通知,

PCB 里记录了哪些通知被屏蔽、哪些已经收到但没处理、以及每种通知该怎么应对。

像 kill -9 这种命令,本质上就是内核往进程的 PCB 里塞一个"必须立刻死"的信号,

进程连反抗的机会都没有


9、资源使用统计

最后,PCB 还保存了进程在运行过程中产生的资源使用统计信息,例如占用的 CPU 时间、上下文切换次数以及内存使用情况。这些数据既可用于系统调度决策,也为系统监控和性能分析工具提供了基础。

  • 用户态 CPU 时间

  • 内核态 CPU 时间

  • 上下文切换次数

  • 使用的内存量

top / htop 的数据来源之一。


一个简化版 PCB 结构(示意)

复制代码
struct task_struct {
    pid_t pid;
    long state;
    int priority;

    struct mm_struct *mm;        // 内存
    struct files_struct *files;  // 打开的文件
    struct signal_struct *signal;// 信号

    struct task_struct *parent;
    struct list_head children;

    struct thread_struct thread; // CPU 上下文
};

⚠️ 实际 Linux 的 task_struct 非常大,但核心思想就是这些。


好,给你一版只保留核心、好记不绕弯的总结 👇

(面试 / 实操都够用)


常用的进程查看命令

ps ------ 看"快照"

看某一时刻的进程状态

复制代码
ps aux
ps -ef
  • 看进程号(PID)

  • 看用户

  • 看 CPU / 内存

  • 看命令行

ps 看"这一刻有哪些进程"


top ------ 实时监控

动态看进程变化

复制代码
top
  • 实时 CPU / 内存

  • 排序(P 按 CPU,M 按内存)

  • 可直接 k 杀进程

top 是动态版 ps


二、按"目标"查进程(实用)

pgrep ------ 按名字找 PID

复制代码
pgrep nginx

不知道 PID,用它找


ps + grep ------ 经典组合

复制代码
ps aux | grep nginx

老派但通用


pstree ------ 看父子关系

复制代码
pstree -p

看谁 fork 了谁(后台进程 / 守护进程必用)


三、和信号 / 控制相关(你前面那章的延伸)

kill ------ 发信号

复制代码
kill PID        # 默认 SIGTERM
kill -9 PID     # SIGKILL(强制)

本质是"往 PCB 里塞信号"


jobs / fg / bg ------ shell 作业控制

复制代码
jobs
fg %1
bg %1

只管当前 shell 启动的进程

相关推荐
ajassi20001 小时前
AI语音智能体开发日记(十八)智能体服务器xiaozhi-esp32-server源码部署指南
运维·服务器·人工智能·ai·ai编程
‎ദ്ദിᵔ.˛.ᵔ₎1 小时前
linux 进程信号(下)
linux·运维·服务器
skywalk81631 小时前
在FreeBSD系统的linux仿真环境下安装和使用kiro 这个亚马逊的AI agent
linux·人工智能·freebsd·kiro
Mikko71 小时前
Linux 磁盘满了但 du 找不到?LVM 扩容 df 不变?fstab 写错开不了机?三台真机实测磁盘排查
linux·运维·centos
蓝胖的四次元口袋1 小时前
Jenkins知识梳理(2)
运维·jenkins
yumgpkpm2 小时前
Acceldata ODP 3.3.6.4 vs CDP Private Cloud Base 7.3.2 对比
大数据·运维·服务器·hadoop·华为·zookeeper·hbase
Madison-No72 小时前
多语言聊天大模型--测试报告
linux·git·python·selenium·jmeter·自动化·postman
Liuqy-052 小时前
特殊进程——孤儿、僵尸、守护进程
linux·运维·服务器
流浪0012 小时前
Linux系统篇47——线程(十二) POSIX 信号量与环形队列,把判空判满提前到访问之前
linux·操作系统·线程·信号量·环形队列
咖丨喱2 小时前
【MMC Core + hc16 Host(WiFi SDIO 如何落到控制器)】
linux