教程 linux tutorial

Linux 进程管理概述 - 进程理论与系统基础

1. 进程基础概念

1.1 什么是进程

在 Linux 系统中,进程(Process)是程序在执行时的一个实例。当用户运行一个程序时,操作系统会加载程序到内存,并创建一个进程来管理该程序的执行。每个进程都有自己独立的地址空间、资源和状态。

1.2 进程与程序的区别

  • 程序:是存储在磁盘上的可执行文件,是静态的代码和数据
  • 进程:是程序执行的实例,是动态的,有生命周期和状态变化
  • 一个程序可以同时被多个用户运行,生成多个进程

1.3 进程 ID (PID)

每个进程在创建时都会被分配一个唯一的进程标识符(Process ID,PID)。PID 是一个非负整数,用于在系统中唯一标识一个进程。

  • init 或 systemd 进程是系统启动的第一个进程,PID 为 1
  • 内核线程的 PID 通常为负数
  • 当进程终止后,其 PID 可以被重新分配给新进程(但有延迟机制避免混淆)

1.4 进程类型

在 Linux 系统中,进程可以分为以下几种类型:

  • 用户进程:由用户启动的普通进程
  • 系统进程:由操作系统创建和管理的进程
  • 守护进程:在后台运行,不与任何控制终端关联的进程
  • 内核线程:直接在操作系统内核中运行的特殊进程

1.5 进程状态

Linux 进程具有多种状态,反映了进程当前的运行情况:

  • R (Running):进程正在运行或在就绪队列中等待运行
  • S (Sleeping):进程处于可中断睡眠状态,等待某个事件发生
  • D (Disk Sleep):进程处于不可中断睡眠状态,通常在进行 I/O 操作
  • T (Stopped):进程被暂停,可以通过信号恢复运行
  • Z (Zombie):进程已终止,但父进程尚未回收其资源
  • X (Dead):进程已死亡,这是一个瞬时状态,通常看不到
  • I (Idle):内核线程的空闲状态

2. 进程的生命周期

2.1 进程的创建

在 Linux 系统中,进程主要通过以下方式创建:

  • fork():创建一个与父进程几乎相同的新进程
  • vfork():与 fork() 类似,但有更多限制,主要用于创建子进程后立即调用 exec()
  • clone():创建线程或具有特定共享资源的进程
  • exec():用新程序替换当前进程的代码和数据,但保留进程 ID 和其他属性

2.2 进程树

Linux 系统中的进程形成一个树形结构,其中:

  • 父进程:创建其他进程的进程
  • 子进程:被其他进程创建的进程
  • 祖先进程:所有上级进程
  • 子后代进程:所有下级进程

每个进程(除了初始进程)都有一个父进程,可以有多个子进程。

2.3 进程终止

进程终止的主要方式有:

  • 正常终止:
    • 程序执行完成并返回退出状态
    • 调用 exit() 或 _exit() 函数
    • 主函数 return 语句
  • 异常终止:
    • 接收到终止信号(如 SIGTERM、SIGKILL)
    • 执行非法操作(如访问无效内存)导致信号(如 SIGSEGV)
    • 严重错误(如除以零)

2.4 僵尸进程与孤儿进程

  • 僵尸进程:进程已终止,但父进程尚未调用 wait() 或 waitpid() 回收其资源,系统中仍保留其进程表项
  • 孤儿进程:父进程先于子进程终止的进程,这些进程会被 init/systemd 进程(PID 1)接管

3. 进程调度

3.1 调度器概述

Linux 调度器负责决定哪个进程能够获得 CPU 时间,它是操作系统核心功能之一。现代 Linux 使用完全公平调度器(Completely Fair Scheduler,CFS)作为默认调度器。

3.2 调度策略

Linux 支持多种调度策略:

  • SCHED_NORMAL (SCHED_OTHER):默认的分时调度策略,用于普通进程
  • SCHED_FIFO:先进先出实时调度策略,优先级高的进程一直运行直到阻塞或主动让出 CPU
  • SCHED_RR:轮询实时调度策略,类似于 FIFO,但添加了时间片限制
  • SCHED_BATCH:批处理调度策略,适合计算密集型、不需要交互式响应的进程
  • SCHED_IDLE:空闲调度策略,优先级最低,只有在系统空闲时才会运行
  • SCHED_DEADLINE:基于截止时间的调度策略,适合实时任务

3.3 优先级机制

Linux 使用两种优先级概念:

  • nice 值:范围从 -20 到 19,值越小优先级越高
  • 实时优先级:范围从 0 到 99,值越大优先级越高

普通进程使用 nice 值,实时进程使用实时优先级。

3.4 进程优先级调整

可以通过以下方式调整进程优先级:

  • nice 命令:启动具有特定 nice 值的进程
  • renice 命令:调整正在运行进程的 nice 值
  • chrt 命令:设置或获取实时进程的调度策略和优先级

4. 内存管理

4.1 进程地址空间

每个 Linux 进程都有自己独立的虚拟地址空间,通常分为以下几个部分:

  • 文本段(Text Segment):存储可执行代码
  • 数据段(Data Segment):存储初始化的全局变量和静态变量
  • BSS 段(Block Started by Symbol):存储未初始化的全局变量和静态变量
  • 堆(Heap):动态内存分配区域
  • 栈(Stack):存储局部变量、函数调用信息

4.2 内存分配

Linux 进程内存分配主要通过以下机制:

  • malloc/free:C 语言标准库函数,管理用户空间的内存分配
  • brk/sbrk:系统调用,调整进程数据段的大小
  • mmap:内存映射系统调用,可以将文件或设备映射到进程地址空间

4.3 内存使用统计

Linux 提供了多种工具来监控进程的内存使用情况:

  • /proc/PID/status:包含进程的内存使用统计信息
  • /proc/PID/statm:包含进程的内存使用详细统计
  • top, htop:交互式进程监控工具,显示内存使用情况
  • ps aux:显示进程的内存使用率

5. 进程间通信

5.1 进程间通信概述

Linux 提供了多种进程间通信(IPC)机制,使不同进程能够交换数据和同步操作。

5.2 管道(Pipes)

管道是最简单的 IPC 机制之一,分为:

  • 匿名管道:通过 pipe() 系统调用创建,只能用于有亲缘关系的进程间通信
  • 命名管道(FIFO):通过 mkfifo() 或 mknod() 创建,允许无亲缘关系的进程间通信

5.3 信号(Signals)

信号是异步通知机制,用于通知进程发生了特定事件:

  • 常用信号:SIGTERM(优雅终止)、SIGKILL(强制终止)、SIGINT(中断信号)
  • 信号处理:进程可以捕获、忽略或默认处理信号

5.4 消息队列(Message Queues)

消息队列允许进程以消息的形式交换数据,具有以下特点:

  • 消息有类型和优先级
  • 消息可以在进程间传递,即使发送进程已终止
  • 有一定的系统资源限制

5.5 共享内存(Shared Memory)

共享内存是最快的 IPC 机制,通过以下步骤使用:

  1. 使用 shmget() 创建共享内存段
  2. 使用 shmat() 将共享内存附加到进程地址空间
  3. 进程间直接读写共享内存
  4. 使用 shmdt() 分离共享内存
  5. 使用 shmctl() 控制或删除共享内存

5.6 信号量(Semaphores)

信号量是用于同步和互斥的计数器,主要用于控制对共享资源的访问:

  • 二元信号量:值只能是 0 或 1,用于互斥访问
  • 计数信号量:值可以是任意非负整数,用于控制资源的并发访问数量

5.7 套接字(Sockets)

套接字不仅可以用于网络通信,也可以用于本地进程间通信(Unix 域套接字):

  • Unix 域套接字:使用文件系统路径作为地址
  • 网络套接字:使用 IP 地址和端口号作为地址

6. 进程控制

6.1 进程创建与执行

  • fork():创建子进程
  • exec() 系列函数:执行新程序
  • system():在新进程中执行 shell 命令
  • popen():创建管道连接到命令的标准输入或输出

6.2 进程终止与等待

  • exit()/exit():终止进程
  • wait()/waitpid():等待子进程终止并获取退出状态
  • kill():向指定进程发送信号

6.3 进程组与会话

  • 进程组:一组相关进程的集合,有一个唯一的进程组 ID (PGID)
  • 会话:一组相关进程组的集合,有一个会话 ID (SID)
  • 会话首进程:创建会话的进程
  • 控制终端:与会话关联的终端

7. 守护进程

7.1 守护进程概述

守护进程是在后台运行且不与任何控制终端关联的特殊进程,通常以 d 结尾(如 sshd、httpd)。

7.2 创建守护进程的步骤

标准的守护进程创建过程(也称为 daemonization)包括以下步骤:

  1. 调用 fork() 创建子进程,然后父进程退出
  2. 子进程调用 setsid() 创建新会话,摆脱控制终端
  3. 再次调用 fork(),确保守护进程不是会话首进程,避免重新获取控制终端
  4. 修改工作目录(通常为 /)
  5. 设置文件权限掩码
  6. 关闭所有不需要的文件描述符
  7. 重新定向标准输入、输出和错误到 /dev/null

7.3 系统守护进程

Linux 系统中有许多重要的守护进程:

  • init/systemd:系统初始化进程,管理系统启动和运行
  • sshd:SSH 服务器守护进程,提供安全远程登录
  • cron:定期执行任务的守护进程
  • syslogd/rsyslogd:系统日志守护进程
  • httpd/nginx:Web 服务器守护进程

8. 进程监控与管理工具

8.1 进程状态查看

  • ps:显示当前进程状态
  • top:动态显示进程状态和系统资源使用情况
  • htop:top 的增强版,提供更友好的界面
  • pstree:以树形结构显示进程关系

8.2 进程控制命令

  • kill:向进程发送信号
  • nice/renice:调整进程优先级
  • bg/fg:管理后台和前台作业
  • jobs:显示当前 shell 的作业列表

8.3 系统资源监控

  • vmstat:显示虚拟内存统计信息
  • iostat:显示 CPU 和 I/O 统计信息
  • netstat/ss:显示网络连接、路由表等网络统计信息
  • free:显示内存使用情况
  • mpstat:显示处理器相关统计信息

9. 总结

Linux 进程管理是操作系统的核心功能之一,涉及进程的创建、执行、调度、通信和终止等多个方面。通过本文的学习,您应该对 Linux 进程的基本概念、生命周期、调度机制、内存管理和进程间通信有了全面的了解。

掌握 Linux 进程管理的理论知识对于系统管理员、开发人员和安全专家来说都非常重要。它不仅有助于理解系统的工作原理,也为使用各种进程管理工具和编写高效程序提供了理论基础。

在后续的章节中,我们将详细介绍各种进程管理命令的使用方法和最佳实践,帮助您更好地管理和优化 Linux 系统中的进程。