Ubuntu 22.04中的进程管理详解
进程管理是Linux系统管理的核心。一个进程是程序的一个执行实例,理解如何查看、控制和调度进程是任何Linux用户或管理员的必备技能。
1. Linux进程概述
1.1 进程的概念
知识点:
- 进程: 是一个正在执行的程序实例。它不仅仅是程序代码,还包括程序当前的活动、一组资源(如打开的文件、处理器状态、内存地址空间等)。
- 程序 : 是一个静态的文件,包含了一组指令,存储在磁盘上。当程序被加载到内存并开始执行时,它就变成了一个或多个进程。
比喻: - 程序 = 食谱(静态的指令列表)。
- 进程 = 按照食谱正在烹饪的菜肴(动态的、有状态的执行过程)。
1.2 程序和进程
知识点:
- 一个程序可以同时对应多个进程。例如,多个用户可能同时运行同一个
/bin/bash程序,但每个用户都有一个独立的bash进程。 - 进程有生命周期:创建(
fork)、执行(exec)、等待、终止(exit)。
1.3 进程的状态
知识点:
在Linux中,进程在其生命周期中会处于不同的状态。ps命令会显示这些状态的缩写:
- R (Running/Runnable): 正在运行或在运行队列中等待运行。
- S (Sleeping): 可中断的睡眠。进程正在等待某个事件完成(如等待用户输入、网络数据),可以被信号唤醒。
- D (Uninterruptible Sleep): 不可中断的睡眠。通常在等待I/O操作(如磁盘读写),不能被信号唤醒。这保证了I/O操作的完整性。
- T (Stopped/Traced) : 已停止。进程被暂停,通常是由于收到了
SIGSTOP信号或正在被调试器跟踪。 - Z (Zombie): 僵尸进程。进程已终止,但其父进程尚未读取其退出状态。僵尸进程几乎不占用系统资源,只是在进程表中保留一个位置。
- X (Dead) : 已死。进程已从系统中移除(
ps通常看不到此状态)。
1.4 进程的分类
知识点:
可以从不同角度对进程进行分类:
- 按用户分类 :
- 系统进程 : 由内核在系统启动时创建,负责管理底层硬件和系统服务(如
kthreadd,systemd)。 - 用户进程 : 由用户启动,用于执行特定任务(如
bash,firefox,gcc)。
- 系统进程 : 由内核在系统启动时创建,负责管理底层硬件和系统服务(如
- 按服务模式分类 :
- 前台进程: 与终端关联,能接收用户输入。通常一次只能有一个前台进程。
- 后台进程: 不与终端直接交互,在后台默默运行。
1.5 进程优先级
知识点:
Linux是一个多任务操作系统,CPU时间需要分配给多个进程。进程优先级决定了CPU调度器分配给它的处理时间的多少。
- 优先级范围 : 通常是
-20到19。 - 数值含义 : 数值越小,优先级越高 。
-20是最高优先级,19是最低优先级。 - Nice值 (NI) : 优先级通常用"Nice值"表示。普通用户只能降低自己进程的优先级(增大Nice值),只有
root用户可以提高任何进程的优先级(减小Nice值)。 - PR值 :
ps或top命令中显示的PR是内核的最终优先级值,它与Nice值有关,但不是简单的映射关系。
2. 进程状态监测
2.1 静态监控:ps 命令
知识点:
ps (Process Status) 命令用于查看当前时刻的进程快照。它有非常多的选项,最常用的组合是 ps aux 和 ps -ef。
语法知识点:
ps aux: 使用BSD风格语法。a: 显示所有终端上的所有进程。u: 以用户为中心的格式显示(包括用户、CPU、内存使用率等)。x: 显示没有控制终端的进程。
ps -ef: 使用System V风格语法。-e: 显示所有进程。-f: 显示完整格式列表。
案例代码:
bash
# 使用 ps aux 查看所有进程的详细信息
$ ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# root 1 0.0 0.3 168736 11920 ? Ss 10:00 0:01 /sbin/init splash
# user 1234 0.5 2.1 3000000 80000 ? Sl 10:05 0:10 /usr/lib/firefox/firefox
# ...
# USER: 进程所有者
# PID: 进程ID (Process ID),唯一标识
# %CPU: CPU使用率
# %MEM: 内存使用率
# VSZ: 虚拟内存大小
# RSS: 驻留集大小,实际占用的物理内存
# TTY: 关联的终端,?表示无终端
# STAT: 进程状态 (R, S, D, T, Z等)
# START: 启动时间
# TIME: 累计CPU使用时间
# COMMAND: 启动进程的命令
# 使用 ps -ef 查看所有进程,更侧重于父子关系
$ ps -ef
# UID PID PPID C STIME TTY TIME CMD
# root 1 0 0 10:00 ? 00:00:01 /sbin/init splash
# user 1234 1100 0 10:05 ? 00:00:10 /usr/lib/firefox/firefox
# ...
# UID: 用户ID
# PID: 进程ID
# PPID: 父进程ID (Parent Process ID)
# C: CPU使用率
# STIME: 启动时间
# TTY: 终端
# TIME: CPU时间
# CMD: 命令
# 查找特定进程,例如查找所有 sshd 进程
$ ps aux | grep sshd
# root 1500 0.0 0.1 15000 5000 ? Ss 10:01 0:00 /usr/sbin/sshd -D
# user 2500 0.0 0.2 16000 6000 pts/0 S+ 10:30 0:00 ssh user@192.168.1.10
2.2 动态监控:top 命令
知识点:
top 命令提供了一个动态的、实时更新的视图,显示系统资源使用情况和进程列表。它是系统管理员进行性能分析的首选工具。
语法知识点:
- 启动后,
top会进入一个交互式界面。 - 常用交互命令 :
M: 按内存使用率排序。P: 按CPU使用率排序(默认)。T: 按累计时间排序。u: 跟踪特定用户的进程。k: 杀死一个进程(需要输入PID)。q: 退出top。1: 切换显示单个CPU核心的详细信息。
案例代码:
bash
# 启动 top 命令
$ top
# top - 10:45:30 up 2 days, 15:20, 2 users, load average: 0.15, 0.20, 0.10
# Tasks: 200 total, 1 running, 199 sleeping, 0 stopped, 0 zombie
# %Cpu(s): 5.0 us, 2.0 sy, 0.0 ni, 92.0 id, 1.0 wa, 0.0 hi, 0.0 si, 0.0 st
# KiB Mem : 8000000 total, 6000000 free, 1000000 used, 1000000 buff/cache
# KiB Swap: 4000000 total, 4000000 free, 0 used. 7000000 avail Mem
#
# PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
# 1234 user 20 0 3000000 80000 60000 S 5.0 1.0 0:10.15 firefox
# 5678 root 20 0 15000 5000 4000 S 0.5 0.1 0:00.05 systemd
# ...
# 顶部信息区:
# load average: 系统负载,1分钟、5分钟、15分钟内的平均任务队列长度
# Tasks: 进程总数、运行中、睡眠中、停止、僵尸
# %Cpu(s): CPU使用情况分解 (us用户空间, sy内核空间, niNice值, id空闲, wa等待I/O)
# KiB Mem/KiB Swap: 内存和交换分区使用情况
# 进程列表区:
# PR: 优先级
# NI: Nice值
# VIRT: 虚拟内存
# RES: 物理内存
# SHR: 共享内存
# S: 状态
# %CPU, %MEM: CPU和内存使用率
# TIME+: 累计CPU时间
2.3 查看进程树:pstree 命令
知识点:
pstree 命令以树状结构显示进程,清晰地展示了进程间的父子关系。
语法知识点:
-p: 显示进程ID。-u: 显示用户切换。-a: 显示命令行参数。
案例代码:
bash
# 显示当前用户的进程树
$ pstree
# 显示所有进程的PID和用户
$ pstree -p -u
# 示例输出:
# systemd(1)─┬─NetworkManager(678)───{NetworkManager}(681)
# ├─sshd(1000)───sshd(1500)───bash(1501)───pstree(2500)
# └─(sd-pam)
# systemd(1)是所有进程的父进程
# sshd(1000)是sshd(1500)的父进程
# bash(1501)是pstree(2500)的父进程
2.4 列出进程打开的文件:lsof 命令
知识点:
lsof (List Open Files) 是一个强大的工具,用于列出当前系统打开的文件。在Linux中,"一切皆文件",包括网络连接、管道、设备等。因此lsof功能非常强大。
案例代码:
bash
# 列出所有进程打开的所有文件 (输出非常多)
$ sudo lsof
# 查看某个特定进程打开了哪些文件 (需要PID)
$ sudo lsof -p 1234
# 查看某个文件被哪个进程打开
$ sudo lsof /var/log/syslog
# 查看某个用户打开的所有文件
$ sudo lsof -u user
# 查看某个端口被哪个进程占用 (非常常用)
$ sudo lsof -i :22
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# sshd 1000 root 3u IPv4 20000 0t0 TCP *:ssh (LISTEN)
# sshd 1000 root 4u IPv6 20001 0t0 TCP *:ssh (LISTEN)
3. 进程状态控制
3.1 调整进程优先级:nice 命令
知识点:
nice 命令用于在启动 一个新进程时,指定它的Nice值。
语法知识点:
nice -n <Nice值> <命令>- 如果不指定
-n,默认Nice值为10。
案例代码:
bash
# 以默认的Nice值10启动一个低优先级的进程
$ nice gzip large_file.tar
# 以更高的优先级(Nice值为-5)启动一个进程 (需要root权限)
$ sudo nice -n -5 ./my_cpu_intensive_app
# 以最低优先级启动一个进程
$ nice -n 19 find / -name "*.log"
3.2 改变运行进程优先级:renice 命令
知识点:
renice 命令用于修改一个正在运行 的进程的Nice值。
语法知识点:
renice <Nice值> -p <PID>- 普通用户只能增加Nice值(降低优先级)。
案例代码:
bash
# 首先用 ps 或 top 找到进程的PID,假设为 2500
$ ps aux | grep my_app
# 将PID为2500的进程的Nice值调整为15 (降低其优先级)
$ renice 15 -p 2500
# 将PID为2500的进程的Nice值调整为-5 (提高其优先级,需要root权限)
$ sudo renice -5 -p 2500
3.3 向进程发送信号:kill 命令
知识点:
kill 命令用于向指定的进程发送信号。虽然名字叫"kill",但它可以发送多种信号,不仅仅是终止信号。
语法知识点:
kill -<信号> <PID>- 常用信号:
15(SIGTERM): 优雅地终止信号。进程可以捕获此信号,在退出前完成清理工作。这是kill的默认信号。9(SIGKILL): 强制终止信号。进程无法忽略,立即被内核终止。这是最后的手段。19(SIGSTOP): 停止进程,类似于Ctrl+Z。18(SIGCONT): 继续运行已停止的进程。
案例代码:
bash
# 向PID为1234的进程发送默认的SIGTERM信号,请求其优雅退出
$ kill 1234
# 如果进程无响应,强制杀死PID为1234的进程
$ kill -9 1234
# 停止PID为5678的进程
$ kill -19 5678
# 继续运行PID为5678的进程
$ kill -18 5678
# 列出所有可用的信号
$ kill -l
3.4 通过名字杀死进程:killall 命令
知识点:
killall 命令可以根据进程名来发送信号,而不是PID。这在你知道进程名但不想先查找PID时很方便。
语法知识点:
killall -<信号> <进程名>
案例代码:
bash
# 优雅地杀死所有名为 firefox 的进程
$ killall firefox
# 强制杀死所有名为 sshd 的进程 (危险操作,需谨慎)
$ sudo killall -9 sshd
# 向所有名为 my_app 的进程发送停止信号
$ killall -19 my_app
4. 进程启动与作业控制
作业控制是Shell的一个功能,允许用户管理多个进程(作业),包括将它们在前台和后台之间切换。
4.1 进程的启动
- 前台启动: 直接在终端输入命令,Shell会等待命令执行完毕,期间终端被占用。
- 后台启动 : 在命令后添加
&符号,Shell会立即返回,进程在后台运行。
案例代码:
bash
# 前台启动,终端被占用
$ sleep 300
# 后台启动,Shell立即返回,并给出作业号和PID
$ sleep 300 &
# [1] 3001
# [1] 表示作业号
# 3001 表示进程ID
4.2 进程的挂起
知识点:
在前台运行的进程可以通过按键 Ctrl+Z 挂起(暂停),并将其放入后台。
案例代码:
bash
# 前台启动一个进程
$ sleep 300
# 按下 Ctrl+Z
# ^Z
# [1]+ Stopped sleep 300
# 进程被挂起,并放入后台作业列表
4.3 使用 jobs 命令显示任务状态
知识点:
jobs 命令用于显示当前Shell会话中的所有后台作业。
案例代码:
bash
$ jobs
# [1]+ Stopped sleep 300
# [2]- Running ping google.com &
# [1]+ 表示最近的一个作业
# [2]- 表示次近的一个作业
# Stopped 表示被挂起
# Running 表示正在后台运行
4.4 使用 fg 命令将任务移至前台
知识点:
fg (foreground) 命令可以将后台作业调到前台继续运行。
案例代码:
bash
# 将最近的后台作业(作业号1)调到前台
$ fg %1
# 或者直接 fg (默认调最近的)
$ fg
# sleep 300 进程会重新在前台运行
4.5 使用 bg 命令将任务移至后台
知识点:
bg (background) 命令可以将一个被挂起的作业在后台继续运行。
案例代码:
bash
# 假设 sleep 300 已被 Ctrl+Z 挂起
$ jobs
# [1]+ Stopped sleep 300
# 让它在后台继续运行
$ bg %1
# [1]+ sleep 300 &
$ jobs
# [1]+ Running sleep 300 &
4.6 使用 nohup 命令启动脱离终端运行的任务
知识点:
nohup (No Hang Up) 命令可以让进程忽略SIGHUP信号(挂断信号,通常在终端关闭时发送给其子进程)。这使得进程在你退出Shell后仍能继续运行。其输出通常会重定向到 nohup.out 文件。
案例代码:
bash
# 启动一个长时间运行的脚本,并使其在终端关闭后依然运行
$ nohup ./my_long_running_script.sh &
# 输出:
# nohup: ignoring input and appending output to 'nohup.out'
# 即使你关闭了SSH连接,脚本也会继续在服务器上运行
# 你可以重新登录后,用 ps aux | grep my_long_running_script.sh 来查找它
5. 本章小结
本章详细讲解了Ubuntu 22.04中进程管理的方方面面。我们从进程的基本概念(状态、分类、优先级)入手,学习了如何使用 ps, top, pstree, lsof 等工具来监控进程状态。接着,我们掌握了如何使用 nice, renice, kill, killall 来控制进程的优先级和生命周期。最后,我们探讨了Shell的作业控制功能,包括前后台任务的切换和使用 nohup 运行持久化任务。
掌握这些知识点和命令,是成为一名高效的Linux用户或管理员的必经之路,它将赋予你精确控制和洞察系统运行状态的能力。