Linux 进程管理详解:从概念到实战

1. 进程概念

1.1 程序与进程

  • 程序:存放在外存中的一段代码的集合,是静态的,只是一个文件。
  • 进程:程序动态执行的过程,包括进程的创建、调度、消亡。

一个程序可以对应多个进程,例如各种软件支持多用户同时登录。

1.2 进程相关命令

命令 作用
top 根据 CPU 占用率实时查看系统运行的进程
ps -ef 打印当前进程信息(不实时刷新)
`ps -ef grep *.out`
pstree 查看进程关系树
ps -aux 查看进程状态
kill 杀死进程任务(发送信号)
kill -l 查看 kill 支持的信号配置
kill -信号编号 进程PID 向指定进程发送指定信号

进程关键字段:

  • PID:进程的 ID 号,唯一区分进程的标识(不是名字)。
  • PPID:父进程的 ID 号。
  • USER:进程发起所使用的用户。

1.3 常用信号

SIGSEGV(段错误)

  • 信号编号:11
  • 含义:程序试图访问不允许访问的内存区域。
  • 结果:程序崩溃,产生 Segmentation Fault 错误。

SIGKILL(强制终止信号)

  • 信号编号:9
  • 作用:立即终止进程,强制结束。
  • 特点:无法被捕获、阻塞或忽略。

1.4 前后台任务管理

命令 作用
./a.out & 后台执行任务
jobs 查看后台的任务
ps 查看终端下的前后台任务
fg 编号 将后台任务放到前台

1.5 进程优先级(NI)

  • Linux 中值越小优先级越高,Windows 中相反。
  • 默认优先级为 10
命令 作用
nice -n 10 ./a.out 以指定优先级开启进程
renice -n 优先级 进程PID 更改运行中进程的优先级

2. 进程的创建

2.1 虚拟地址空间

  • 32 位系统:4GB(2^32)
  • 64 位系统:16EB(2^64,实际通常用 48 位 = 256TB)

进程空间划分:

说明
文本段(.text) 代码以及指令(只读)
已初始化数据段(.data) 已初始化的全局变量
未初始化数据段(.bss) 未初始化的全局变量(加载后清零)
字符串常量区(.rodata) 字符串常量
堆(Heap) 向上增长,malloc 分配
栈(Stack) 向下增长,局部变量、函数调用
内核空间 用户态无法访问,只读

进程空间特性:

  • 进程空间是独立的,每个进程独享进程空间。
  • 所有进程共享 0-4G 虚拟内存。
  • 分时复用,同一虚拟空间不同进程数据不重叠。
  • MMU 将虚拟地址空间映射为实际的物理空间。
text 复制代码
┌─────────────────────────────┐ 高地址 (0xFFFFFFFF)
│        内核空间             │ ← 用户态无法访问
│    (Kernel Space)           │   只读
├─────────────────────────────┤
│                             │
│        栈 (Stack)           │ ← 向下增长
│         ↓                   │   局部变量、函数调用
│                             │
├─────────────────────────────┤
│         空洞                │
│       (未使用)              │
├─────────────────────────────┤
│                             │
│         堆 (Heap)           │ ← 向上增长
│         ↑                   │   malloc 分配
│                             │
├─────────────────────────────┤
│    字符串常量区(.rodata)   │ ← 字符串常量
├─────────────────────────────┤
│   未初始化数据段 (.bss)      │ ← 未初始化的全局变量
├─────────────────────────────┤
│   已初始化数据段 (.data)     │ ← 初始化的全局变量
├─────────────────────────────┤
│       代码段 (.text)        │ ← 程序代码(只读)
│                             │
└─────────────────────────────┘ 低地址 (0x00000000)

3. 进程的调度

3.1 调度算法演进

  1. 先来先服务:以前先来先执行,后来后执行。
  2. 短作业优先:后来短作业优先调度。
  3. 高优先级调度:后来高优先级调度。
  4. 时间片轮转(当前):中断当前操作 → 保存现场 → 切换任务 → 恢复现场 → 继续任务。
  5. 多级队列反馈:未来方向。
  6. 负载均衡:未来方向。

时间片 :CPU 在进程任务中执行的一小段时间。

宏观并行,微观串行

3.2 进程状态

状态 说明
就绪态(R) 没有被 CPU 轮转到的正在等待执行的任务
运行态(R) 正在被 CPU 执行的任务
可唤醒等待态(S) 由于缺少资源让程序暂时挂起的状态
不可唤醒等待态(D) 等待过程中不可被唤醒(人为延时、条件触发等)
停止态(T) 系统需要让进程暂停(如 debug 调试)
僵尸态(Z) 进程代码已执行完,空间未被回收(应尽量避免)
结束态(X) 代码执行结束,空间被回收的那一时刻

4. 进程相关函数接口

4.1 fork 函数

c 复制代码
#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

功能:

  • 创建一个子进程空间,调用进程被认为是子进程的父进程。
  • 子进程是父进程的完整副本(代码、数据、堆、栈、文件描述符、缓存等)。
  • 数据一样,但相互独立。
  • 父子进程从 fork() 返回后各自独立运行。

参数: 缺省

返回值:

  • 成功:父进程返回子进程的 PID,子进程返回 0。
  • 失败:返回 -1。

4.2 fork 示例代码

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t pid = fork();

    if (pid == -1) {
        perror("fork failed");
        return 1;
    }

    if (pid == 0) {
        // 子进程代码
        printf("子进程: PID = %d, 父进程 PID = %d\n",
                getpid(), getppid());
    } else {
        // 父进程代码
        printf("父进程: PID = %d, 子进程 PID = %d\n",
                getpid(), pid);
    }

    return 0;
}

运行结果示例:

text 复制代码
父进程: PID = 1234, 子进程 PID = 1235
子进程: PID = 1235, 父进程 PID = 1234

4.3 写时复制(Copy-on-Write, COW)

  • 每个进程都有一个独立的页表,存储该进程虚拟地址到物理地址的映射。
  • 进程切换时,CPU 加载对应进程的页表基址(CR3 寄存器),实现地址转换的切换。
  • 同一虚拟地址在不同进程中指向不同的物理地址,但不会混淆。
  • 父地址与子地址相同,当子进程复制父进程虚拟地址后,物理地址权限更新为只读。
  • 子进程按照虚拟地址写入时触发 COW,复制新的物理地址给子进程的独立页表。
  • 子进程与父进程的地址一样,但指向不同的物理地址。

关键理解 :刚 fork() 完,子进程直接读取父进程的物理内存地址(共享的),并没有复制数据;只有当子进程(或父进程)试图修改时,才会触发复制,复制出一份独立的物理页。
#mermaid-svg-StK4roa51kIrM3t9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-StK4roa51kIrM3t9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-StK4roa51kIrM3t9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-StK4roa51kIrM3t9 .error-icon{fill:#552222;}#mermaid-svg-StK4roa51kIrM3t9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-StK4roa51kIrM3t9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-StK4roa51kIrM3t9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-StK4roa51kIrM3t9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-StK4roa51kIrM3t9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-StK4roa51kIrM3t9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-StK4roa51kIrM3t9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-StK4roa51kIrM3t9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-StK4roa51kIrM3t9 .marker.cross{stroke:#333333;}#mermaid-svg-StK4roa51kIrM3t9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-StK4roa51kIrM3t9 p{margin:0;}#mermaid-svg-StK4roa51kIrM3t9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-StK4roa51kIrM3t9 .cluster-label text{fill:#333;}#mermaid-svg-StK4roa51kIrM3t9 .cluster-label span{color:#333;}#mermaid-svg-StK4roa51kIrM3t9 .cluster-label span p{background-color:transparent;}#mermaid-svg-StK4roa51kIrM3t9 .label text,#mermaid-svg-StK4roa51kIrM3t9 span{fill:#333;color:#333;}#mermaid-svg-StK4roa51kIrM3t9 .node rect,#mermaid-svg-StK4roa51kIrM3t9 .node circle,#mermaid-svg-StK4roa51kIrM3t9 .node ellipse,#mermaid-svg-StK4roa51kIrM3t9 .node polygon,#mermaid-svg-StK4roa51kIrM3t9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-StK4roa51kIrM3t9 .rough-node .label text,#mermaid-svg-StK4roa51kIrM3t9 .node .label text,#mermaid-svg-StK4roa51kIrM3t9 .image-shape .label,#mermaid-svg-StK4roa51kIrM3t9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-StK4roa51kIrM3t9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-StK4roa51kIrM3t9 .rough-node .label,#mermaid-svg-StK4roa51kIrM3t9 .node .label,#mermaid-svg-StK4roa51kIrM3t9 .image-shape .label,#mermaid-svg-StK4roa51kIrM3t9 .icon-shape .label{text-align:center;}#mermaid-svg-StK4roa51kIrM3t9 .node.clickable{cursor:pointer;}#mermaid-svg-StK4roa51kIrM3t9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-StK4roa51kIrM3t9 .arrowheadPath{fill:#333333;}#mermaid-svg-StK4roa51kIrM3t9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-StK4roa51kIrM3t9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-StK4roa51kIrM3t9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-StK4roa51kIrM3t9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-StK4roa51kIrM3t9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-StK4roa51kIrM3t9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-StK4roa51kIrM3t9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-StK4roa51kIrM3t9 .cluster text{fill:#333;}#mermaid-svg-StK4roa51kIrM3t9 .cluster span{color:#333;}#mermaid-svg-StK4roa51kIrM3t9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-StK4roa51kIrM3t9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-StK4roa51kIrM3t9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-StK4roa51kIrM3t9 .icon-shape,#mermaid-svg-StK4roa51kIrM3t9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-StK4roa51kIrM3t9 .icon-shape p,#mermaid-svg-StK4roa51kIrM3t9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-StK4roa51kIrM3t9 .icon-shape .label rect,#mermaid-svg-StK4roa51kIrM3t9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-StK4roa51kIrM3t9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-StK4roa51kIrM3t9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-StK4roa51kIrM3t9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否

父进程调用 fork()
创建子进程空间
子进程共享父进程物理内存(只读)
是否有进程尝试写入?
父子进程继续共享物理页
触发 COW,复制独立物理页
子进程拥有独立物理内存
父子进程独立运行

5. 总结

  • 进程是程序动态执行的过程,拥有独立的虚拟地址空间。
  • Linux 通过时间片轮转实现宏观并行、微观串行。
  • fork() 创建子进程时采用写时复制技术,兼顾效率与隔离。
  • 掌握 pstopkill 等命令是日常进程管理的基础。
相关推荐
画中有画1 小时前
自动化脚本中系统事件和回调函数
运维·自动化
薛定猫AI2 小时前
OpenAI Codex本地完整配置教程|(Windows/Mac/Linux全平台,修复鉴权报错)
linux·windows·macos
敢敢のwings3 小时前
类OpenClaw 网络深度解析:AI Agent 自动化的新范式
运维·人工智能·自动化
IPdodo_3 小时前
代理 IP 服务商 SLA 怎么验?7 项指标与 Python 探测脚本实战
运维·python·网络协议·网络安全·代理ip
云飞云共享云桌面3 小时前
智能装备工厂研发团队如何利用单台服务器承载 10 路 SolidWorks 并发?
运维·服务器·3d·自动化·制造
王琦03183 小时前
haproxy
运维·云原生
辻弋2013 小时前
手动关服务会自动重启、组策略家庭版用不了——Windows Update Blocker用“禁用+锁定”双保险,让Win10/11自动更新彻底闭嘴
服务器·人工智能·windows·电脑·开源软件
发量惊人的中年网工3 小时前
如何验证DDoS高防真的生效?从源站隐藏到正常访问的完整验收方法
运维·网络·数据库·ddos