进程管理¶
在本章中,您将学习如何处理进程。
目标:在本章中,未来的 Linux 管理员将学会如何
识别进程的
PID
和 PPID
;
查看和搜索进程;
管理进程。
进程, linux
知识:
难度:
阅读时间: 20 分钟
概述¶
操作系统由进程组成。这些进程按特定顺序执行并相互关联。进程分为两类:一类专注于用户环境,另一类专注于硬件环境。
当程序运行时,系统会创建一个进程,将程序数据和代码放入内存,并创建一个运行时堆栈。进程是程序的一个实例,具有相关的处理器环境(指令计数器、寄存器等)和内存环境。
每个进程都有
- 一个PID:Process IDentifier,一个唯一的进程标识符
- 一个PPID:Parent 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)。
权限与权利¶
执行命令时,用户的凭据会传递给创建的进程。
默认情况下,进程的实际UID
和 GID
(进程的)与执行命令的用户的实际UID
和 GID
相同。
当在命令上设置SUID
(和/或SGID
)时,实际UID
(和/或GID
)将变为命令所有者(和/或所有者组)的标识,而不是发出命令的用户或用户组的标识。因此,有效和实际的UID是不同的。
每次访问文件时,系统会根据其有效标识符检查进程的权限。
进程管理¶
进程不能无限期地运行,因为这会损害其他正在运行的进程,并妨碍多任务处理。
因此,总的处理时间被分成小段,每个进程(具有优先级)依次访问处理器。进程在其生命周期中会经历几个状态,包括
- 就绪:等待进程可用
- 执行中:正在访问处理器
- 挂起:等待 I/O(输入/输出)
- 停止:等待来自另一个进程的信号
- 僵尸:请求销毁
- 死亡:父进程终止子进程
进程结束的顺序如下
- 关闭打开的文件
- 释放已使用的内存
- 向父进程和子进程发送信号
当父进程死亡时,它们的子进程被称为孤儿。它们将被 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
编号。
fg
和 bg
命令¶
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
列代表
- 作业编号
-
进程运行的顺序
-
+
:当未指定作业编号时,fg
和bg
命令默认选择的进程 -
-
:此进程是下一个获得+
的进程 -
Running(正在运行的进程)或 Stopped(挂起的进程)
- 命令
nice
和 renice
命令¶
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 5
或 renice -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
命令允许实时交互式地控制进程。
pgrep
和 pkill
命令¶
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")进程,已终止但未被其父进程回收