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

本篇为 Linux 系统开发学习笔记,梳理进程核心概念、实操命令、虚拟地址空间、进程创建、调度机制与 C 语言 API 实战,适合 C/C++ 后端、Linux 开发人员阅读。

1. 进程基础概念

1.1 程序与进程

  • 程序 :存储在磁盘外存上的代码文件,属于静态的指令集合。
  • 进程:程序运行起来的动态实例,包含创建、调度、销毁完整生命周期。

一个程序可以对应多个进程,例如服务程序支持多用户访问,会同时启动多个进程实例。

1.2 进程常用操作命令

表格

命令 功能说明
top 实时监控系统进程,默认按 CPU 使用率排序
ps -ef 输出全部进程信息,非实时刷新
`ps -ef grep *.out` 过滤查找指定进程
pstree 树形展示进程父子继承关系
ps -aux 查看进程 CPU、内存、完整运行状态
kill 向进程发送信号,用于终止任务
kill -l 查看全部 kill 信号列表
kill -信号编号 PID 给指定进程发送对应信号

关键字段解析

  • PID:进程唯一标识符,区分进程,不是进程名称
  • PPID:父进程 ID,代表当前进程由哪个进程创建
  • USER:启动该进程的操作系统用户

1.3 常用信号

  1. SIGSEGV(编号 11)段错误 程序访问非法内存地址,直接崩溃,报错:Segmentation Fault
  2. SIGKILL(编号 9)强制终止 立刻强制杀掉进程;无法捕获、阻塞、忽略,属于最高权限信号。

✨实操建议:优先使用kill PID(默认 15 号 SIGTERM,优雅退出);进程卡死无响应时,再使用kill -9 PID强制杀死。

1.4 前后台任务管理

表格

命令 作用
./a.out & 将程序放到后台运行
jobs 查看当前终端后台任务列表
fg 任务编号 把后台任务切回前台执行

1.5 进程优先级 NI

Linux 规则:NI 数值越小,优先级越高,和 Windows 规则相反。 进程默认 NI 值为 10。

表格

命令 作用
nice -n 10 ./a.out 启动程序时指定优先级
renice -n 优先级 PID 修改正在运行进程的优先级

2. 进程创建

2.1 虚拟地址空间

  • 32 位系统:虚拟地址总空间 4GB
  • 64 位系统:理论上限2^64=16EB,内核实际使用 48 位地址,可用最大 256TB

虚拟地址空间分段

表格

说明
.text文本段 机器指令代码,只读属性
.data已初始化数据段 已经赋值的全局变量
.bss未初始化数据段 未初始化全局变量,程序加载后自动清零
.rodata常量区 字符串常量,只读
Heap 堆 向上增长,malloc动态申请内存
Stack 栈 向下增长,存放局部变量、函数调用栈帧
内核空间 用户态程序无权访问,归属操作系统内核

核心要点:

  1. 每个进程拥有独立虚拟地址空间;
  2. MMU 内存管理单元完成虚拟地址到物理地址映射;
  3. 不同进程即便虚拟地址相同,映射到的物理内存也互不干扰。
复制代码
┌─────────────────────────────┐ 高地址 (0xFFFFFFFF)
│        内核空间             │ ← 用户态无法访问
│    (Kernel Space)           │   只读
├─────────────────────────────┤
│        栈 (Stack)           │ ← 向下增长
│         ↓                   │   局部变量、函数调用
├─────────────────────────────┤
│         空洞(未使用)        │
├─────────────────────────────┤
│         堆 (Heap)           │ ← 向上增长
│         ↑                   │   malloc分配
├─────────────────────────────┤
│    字符串常量区(.rodata)     │ ← 字符串常量
├─────────────────────────────┤
│   未初始化数据段(.bss)      │ ← 未初始化全局变量
├─────────────────────────────┤
│   已初始化数据段(.data)     │ ← 初始化全局变量
├─────────────────────────────┤
│       代码段(.text)         │ ← 程序代码(只读)
└─────────────────────────────┘ 低地址 (0x00000000)

3. 进程调度

3.1 调度算法演变

  1. 先来先服务 FCFS:按照任务到达顺序依次执行
  2. 短作业优先 SJF:耗时短的任务优先调度
  3. 高优先级调度:优先级高的任务优先运行
  4. 时间片轮转(Linux 当前核心调度)

执行流程:中断当前进程 → 保存上下文现场 → 切换进程 → 恢复现场继续运行 宏观上多个程序同时运行,微观 CPU 同一时刻只能执行一个进程。

  1. 多级反馈队列、负载均衡:现代 Linux 调度器优化方向

3.2 进程状态

表格

状态标识 状态名称 含义
R 就绪 / 运行态 就绪:等待 CPU 调度;运行:正在 CPU 执行
S 可唤醒等待态 等待 IO 或资源,收到信号可被唤醒
D 不可唤醒等待态 深度阻塞,信号无法打断,常见磁盘 IO 等待
T 停止态 进程被暂停,例如 gdb 调试场景
Z 僵尸态 进程执行完毕,但父进程没有回收资源,残留僵尸进程
X 结束态 进程全部资源回收,彻底销毁

⚠️注意:僵尸进程 Z,子进程结束父进程未调用 wait 回收产生,开发中需要尽量规避。

4. 进程系统调用接口

4.1 fork () 函数

复制代码
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);

功能:创建子进程,调用 fork 的进程为父进程。

  • 子进程会复制父进程全部内容:代码、数据、堆栈、文件描述符;
  • fork 返回之后,父子进程相互独立运行。

返回值

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

4.2 fork 示例代码

复制代码
#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;
}

运行输出示例:

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

4.3 写时复制 COW (Copy‑on‑Write)

fork 不会直接拷贝全部物理内存,是 Linux 重要优化机制。

  1. fork 创建子进程,父子进程共享同一物理内存页,页面标记为只读;
  2. 父或子进程尝试修改内存,触发缺页异常;
  3. 内核复制一份全新物理页给写入进程,更新页表映射,完成内存隔离。

关键点:fork 刚完成,父子共享物理内存;只有发生写操作,才会复制内存,大幅提升 fork 执行效率。

简易逻辑流程:

复制代码
父进程调用fork()
    ↓
创建子进程虚拟地址空间
    ↓
父子共享父进程物理内存(只读权限)
    ↓
是否有进程执行写操作?
├─否 → 继续共享物理页
└─是 → 触发COW,复制独立物理页,父子内存隔离

5. 总结

  1. 进程是程序动态运行实例,拥有独立虚拟地址空间;
  2. Linux 依靠时间片轮转调度,实现宏观并行、微观串行;
  3. fork()创建子进程,借助写时复制 COW 兼顾性能与内存隔离;
  4. 日常运维熟练使用pstopkilljobs等命令;
  5. 开发中要重点防范僵尸进程、D 状态阻塞进程这类异常。
相关推荐
evans在进步44 分钟前
Spring Boot 启动流程与 @SpringBootApplication 核心原理详解
java·spring boot·后端
fatcoder1 小时前
玩转 Redis · Set 篇
前端·redis·后端
爱喝麻油的小哆1 小时前
🐾 Day 5|桌面数字人-接入llm可以对话啦
前端·three.js
许彰午1 小时前
11-rawSql占位符替换
java·低代码·架构
我叫黑大帅1 小时前
关于没有对生产者做校验的思考
前端·面试·架构
桌面运维家1 小时前
信创机房批量换国产终端,服务器IO通道配置实测体验
运维·服务器
掘金者阿豪1 小时前
你的公网 IP 是专线还是动态变化的?一文讲透动态 IP 与固定 IP 的那些事
前端·后端
码匠许师傅1 小时前
【C++ 面试真题】聊聊 C++ 的类型特征( type_traits)
java·c++·面试
java1234_小锋1 小时前
Spring框架的创始人开发了一个Java AI智能体框架
java·人工智能·spring