跳至内容

进程管理

在本章中,您将学习如何处理进程。


目标:在本章中,未来的 Linux 管理员将学会如何

✔ 识别进程的 PIDPPID
✔ 查看和搜索进程;
✔ 管理进程。

🏁 进程, linux

知识⭐ ⭐
难度⭐

阅读时间: 20 分钟


概述

操作系统由进程组成。这些进程按特定顺序执行并相互关联。进程分为两类:一类专注于用户环境,另一类专注于硬件环境。

当程序运行时,系统会创建一个进程,将程序数据和代码放入内存,并创建一个运行时堆栈。进程是程序的一个实例,具有相关的处理器环境(指令计数器、寄存器等)和内存环境。

每个进程都有

  • 一个PIDProcess IDentifier,一个唯一的进程标识符
  • 一个PPIDParent Process IDentifier,父进程的唯一标识符

通过连续的派生,init 进程是所有进程的父进程。

  • 父进程总是创建一个进程
  • 父进程可以有多个子进程

进程之间存在父/子关系。子进程是父进程调用fork() 原始函数并复制其代码以创建子进程的结果。子进程的PID 被返回给父进程,以便它可以与其通信。每个子进程都有其父进程的标识符,即PPID

PID 号表示进程执行时的标识。当进程结束时,该编号可以再次用于另一个进程。多次运行相同的命令每次都会产生不同的PID

注意

进程与线程不同。每个进程都有自己的内存上下文(资源和地址空间),而同一进程中的线程共享此上下文。

查看进程

ps 命令显示正在运行的进程的状态。

ps [-e] [-f] [-u login]

示例

# ps -fu root
选项 描述
-e 显示所有进程。
-f 显示完整格式列表。
-u 登录名 显示用户的进程。

一些附加选项

选项 描述
-g 显示组中的进程。
-t tty 显示来自终端的进程。
-p PID 显示进程信息。
-H 以树形结构显示信息。
-l 以长格式显示。
--sort COL 根据列对结果进行排序。
--headers 在每个终端页面上显示标题。
--format "%a %b %c" 自定义输出显示格式。

如果不指定选项,ps 命令只显示当前终端运行的进程。

结果显示在以下列中

# ps -ef
UID  PID PPID C STIME  TTY TIME      CMD
root 1   0    0 Jan01  ?   00:00/03  /sbin/init
描述
UID 所有者用户。
PID 进程标识符。
PPID 父进程标识符。
C 进程的优先级。
STIME 执行日期和时间。
TTY 执行终端。
TIME 处理时长。
CMD 执行的命令。

控制行为可以完全自定义

# ps -e --format "%P %p %c %n" --sort ppid --headers
 PPID   PID COMMAND          NI
    0     1 systemd           0
    0     2 kthreadd          0
    1   516 systemd-journal   0
    1   538 systemd-udevd     0
    1   598 lvmetad           0
    1   643 auditd           -4
    1   668 rtkit-daemon      1
    1   670 sssd              0

进程类型

用户进程

  • 从与用户关联的终端启动
  • 通过请求或守护进程访问资源

系统进程(守护进程

  • 由系统启动
  • 不与任何终端关联,由系统用户(通常是root)拥有
  • 在启动时加载,驻留在内存中,等待调用
  • 通常以进程名称后面的字母d来标识

因此,系统进程被称为守护进程(D*isk And Execution MON*itor)。

权限与权利

执行命令时,用户的凭据会传递给创建的进程。

默认情况下,进程的实际UIDGID(进程的)与执行命令的用户的实际UIDGID 相同。

当在命令上设置SUID(和/或SGID)时,实际UID(和/或GID)将变为命令所有者(和/或所有者组)的标识,而不是发出命令的用户或用户组的标识。因此,有效和实际的UID不同的。

每次访问文件时,系统会根据其有效标识符检查进程的权限。

进程管理

进程不能无限期地运行,因为这会损害其他正在运行的进程,并妨碍多任务处理。

因此,总的处理时间被分成小段,每个进程(具有优先级)依次访问处理器。进程在其生命周期中会经历几个状态,包括

  • 就绪:等待进程可用
  • 执行中:正在访问处理器
  • 挂起:等待 I/O(输入/输出)
  • 停止:等待来自另一个进程的信号
  • 僵尸:请求销毁
  • 死亡:父进程终止子进程

进程结束的顺序如下

  1. 关闭打开的文件
  2. 释放已使用的内存
  3. 向父进程和子进程发送信号

当父进程死亡时,它们的子进程被称为孤儿。它们将被 init 进程收养,然后被销毁。

进程的优先级

GNU/Linux 属于分时操作系统家族。处理器以分时方式工作,每个进程占用一部分处理器时间。进程按优先级分类

  • 实时进程:优先级为0-99 的进程由实时调度算法调度。
  • 普通进程:优先级动态为100-139 的进程使用完全公平调度算法进行调度。
  • Nice 值:用于调整普通进程优先级的参数。范围为-20-19

进程的默认优先级为0

运行模式

进程可以有两种运行方式

  • 同步:用户在命令执行期间无法访问 shell。命令执行完毕后,命令提示符会再次出现。
  • 异步:进程在后台处理。命令提示符会立即再次显示。

异步模式的限制

  • 命令或脚本不得等待键盘输入
  • 命令或脚本不得在屏幕上返回任何结果
  • 退出 shell 会结束进程

进程管理控制

kill 命令

kill 命令向进程发送停止信号。

kill [-signal] PID

示例

kill -9 1664
代码 信号 描述
2 SIGINT 立即终止进程
9 SIGKILL 中断进程(Ctrl+d
15 SIGTERM 干净地终止进程
18 SIGCONT 恢复进程。使用 SIGSTOP 信号的进程可以使用它继续运行
19 SIGSTOP 挂起进程(停止进程)。此信号的效果等同于Ctrl+z

信号是进程之间通信的手段。kill 命令向进程发送信号。

技巧

可以通过键入命令来获取 kill 命令考虑的完整信号列表

$ man 7 signal

nohup 命令

nohup 允许进程独立于连接启动。

nohup command

示例

nohup myprogram.sh 0</dev/null &

nohup 忽略用户注销时发送的 SIGHUP 信号。

注意

nohup 处理标准输出和错误,但不处理标准输入,因此将其输入重定向到/dev/null

[Ctrl] + [z]

按下 Ctrl+z 键可暂时挂起同步进程。显示刚被挂起的进程编号后,将恢复提示符。

& 指令

& 语句异步执行命令(该命令称为作业),并显示作业编号。然后返回提示符。

示例

$ time ls -lR / > list.ls 2> /dev/null &
[1] 15430
$

作业编号在后台处理时获得,并以方括号显示,后跟 PID 编号。

fgbg 命令

fg 命令将进程置于前台

$ time ls -lR / > list.ls 2>/dev/null &
$ fg 1
time ls -lR / > list.ls 2/dev/null

bg 命令将其置于后台

[CTRL]+[Z]
^Z
[1]+ Stopped
$ bg 1
[1] 15430
$

无论该进程是创建时使用 & 参数放到后台,还是之后使用 Ctrl+z 键放到后台,都可以使用 fg 命令及其作业编号将其带回前台。

jobs 命令

jobs 命令显示后台运行的进程列表并指定它们的作业编号。

示例

$ jobs
[1]- Running    sleep 1000
[2]+ Running    find / > arbo.txt

列代表

  1. 作业编号
  2. 进程运行的顺序

  3. +:当未指定作业编号时,fgbg 命令默认选择的进程

  4. -:此进程是下一个获得 + 的进程

  5. Running(正在运行的进程)或 Stopped(挂起的进程)

  6. 命令

nicerenice 命令

nice 命令允许通过指定优先级来执行命令。

nice priority command

使用示例

nice --adjustment=-5 find / -name "file"

nice -n -5 find / -name "file"

nice --5 find / -name "file"

nice -n 5 find / -name "file"

nice find / -name "file"

root 不同,普通用户只能降低进程的优先级,并且只接受 0 到 19 之间的值。

如上例所示,前三个命令表示将 Nice 值设置为“-5”,而第二个命令是我们的推荐用法。第四个命令表示将 Nice 值设置为“5”。对于第五个命令,不输入任何选项意味着 Nice 值设置为“10”。

技巧

"Nice" 是 "niceness" 的缩写。

直接键入 nice 命令将返回当前 shell 的 Nice 值。

可以通过修改 /etc/security/limits.conf 文件来解除每个用户或组的 Nice 值限制。

renice 命令允许您更改正在运行的进程的优先级。

renice priority [-g GID] [-p PID] [-u UID]

示例

renice -n 15 -p 1664
选项 描述
-g GID 进程所有者组。
-p PID 进程的。
-u UID 进程所有者。

renice 命令作用于现有进程。因此,可以更改特定进程和属于某个用户或组的多个进程的优先级。

技巧

pidof 命令与 xargs 命令(请参阅高级命令课程)结合使用,允许在一个命令中应用新的优先级

$ pidof sleep | xargs renice -n 20

为了适应不同的发行版,您应该尽可能使用类似 nice -n 5renice -n 6 的命令形式。

top 命令

top 命令显示进程及其资源消耗。

$ top
PID  USER PR NI ... %CPU %MEM  TIME+    COMMAND
2514 root 20 0       15    5.5 0:01.14   top
描述
PID 进程标识符。
USER 所有者用户。
PR 进程优先级。
NI Nice 值。
%CPU 处理器负载。
%MEM 内存负载。
TIME+ 处理器使用时间。
COMMAND 执行的命令。

top 命令允许实时交互式地控制进程。

pgreppkill 命令

pgrep 命令搜索正在运行的进程的进程名称,并在标准输出上显示匹配所选标准的PID

pkill 命令将指定的信号(默认为SIGTERM)发送给每个进程。

pgrep process
pkill [option] [-signal] process

示例

  • 获取 sshd 的进程号
pgrep -u root sshd
  • 杀死所有 tomcat 进程
pkill tomcat

注意

在杀死进程之前,最好确切了解它的作用;否则,可能导致系统崩溃或其他不可预测的问题。

除了向相关进程发送信号外,pkill 命令还可以根据终端号结束用户的连接会话,例如

pkill -t pts/1

killall 命令

此命令的功能与 pkill 命令大致相同。用法是 —killall [option] [ -s SIGNAL | -SIGNAL ] NAME。默认信号是SIGTERM

选项 描述
-l 列出所有已知的信号名称
-i 在杀死之前询问确认
-I 不区分大小写地匹配进程名称

示例

killall tomcat

pstree 命令

此命令以树状结构显示进度,其用法为 - pstree [option]

选项 描述
-p 显示进程的 PID
-n 按 PID 对输出进行排序
-h 突出显示当前进程及其祖先
-u 显示 uid 转换
$ pstree -pnhu
systemd(1)─┬─systemd-journal(595)
           ├─systemd-udevd(625)
           ├─auditd(671)───{auditd}(672)
           ├─dbus-daemon(714,dbus)
           ├─NetworkManager(715)─┬─{NetworkManager}(756)
                                └─{NetworkManager}(757)
           ├─systemd-logind(721)
           ├─chronyd(737,chrony)
           ├─sshd(758)───sshd(1398)───sshd(1410)───bash(1411)───pstree(1500)
           ├─tuned(759)─┬─{tuned}(1376)
                       ├─{tuned}(1381)
                       ├─{tuned}(1382)
                       └─{tuned}(1384)
           ├─agetty(763)
           ├─crond(768)
           ├─polkitd(1375,polkitd)─┬─{polkitd}(1387)
                                  ├─{polkitd}(1388)
                                  ├─{polkitd}(1389)
                                  ├─{polkitd}(1390)
                                  └─{polkitd}(1392)
           └─systemd(1401)───(sd-pam)(1404)

孤儿进程和僵尸进程

孤儿进程:当父进程死亡时,它们的子进程被称为孤儿。init 进程会收养这些特殊状态的进程,并收集状态直到它们被销毁。概念上讲,孤儿进程不会造成任何危害。

僵尸进程:子进程完成工作并终止后,其父进程需要调用信号处理函数 wait() 或 waitpid() 来获取子进程的终止状态。如果父进程不这样做,尽管子进程已经退出,它仍然在系统进程表中保留一些退出状态信息。由于父进程无法获取子进程的状态信息,这些进程将继续占用进程表中的资源。我们将处于此状态的进程称为僵尸。

危害

  • 它们占用系统资源,导致机器性能下降。
  • 无法生成新的子进程。

如何检查当前系统中是否存在任何僵尸进程?

ps -lef | awk '{print $2}' | grep Z

这些字符可能出现在此列中

  • D - 不可中断的睡眠(通常是 IO)
  • I - 空闲内核线程
  • R - 正在运行或可运行(在运行队列中)
  • S - 可中断的睡眠(等待某个事件完成)
  • T - 被作业控制信号停止
  • t - 在调试期间被调试器停止
  • W - 分页(自 2.6.xx 内核起无效)
  • X - 已终止(不应出现)
  • Z - 僵尸("zombie")进程,已终止但未被其父进程回收