进程管理¶
在本章中,您将学习如何使用进程。
目标:在本章中,未来的 Linux 管理员将学习如何:
识别进程的 PID
和 PPID
;
查看并搜索进程;
管理进程。
进程,linux
知识性:
复杂度:
阅读时间: 20 分钟
概述¶
操作系统由进程组成。 这些进程以特定的顺序执行并且彼此相关。 有两大类的进程,一类侧重于用户环境,另一类侧重于硬件环境。
当程序运行时,系统将程序数据和代码放入到内存中并创建 运行栈 来创建进程。 因此,进程是程序的一个实例,它具有相关联的处理器环境(顺序计数器、寄存器等)和内存环境。
每个进程都有:
- PID:Process IDentifier,唯一的进程标识符
- PPID:Parent Process IDentifier,父进程的唯一标识符
通过连续的隶属关系,init
进程是所有进程之父。
- 一个进程始终由父进程创建
- 一个父进程可以有多个子进程
进程之间存在父/子关系。 子进程是父进程调用 fork() 原语并复制自己的代码来创建子进程的结果。 子进程的 PID 会返回给父进程,以便父进程与之对话。 每个子进程都有父进程的标识符 PPID 。
PID 数字代表执行时的进程。 当进程结束时,该数字可再次用于另一个进程。 多次运行同一命令将每次产生不同的 PID。!!! note "说明"
请不要将进程与 _线程_ 混淆。 每个进程都有自己的内存上下文(资源和地址空间),而来自同一进程的 _线程_ 则 共享相同的上下文。
查看进程¶
ps
命令显示正在运行的进程的状态。
ps [-e] [-f] [-u login]
示例:
# ps -fu root
选项 | 说明 |
---|---|
-e |
显示所有进程。 |
-f |
显示附加信息。 |
-u login |
显示用户的进程。 |
一些附加选项:
选项 | 说明 |
---|---|
-g |
显示组中的进程。 |
-t tty |
显示从终端运行的进程。 |
-p PID |
显示进程信息。 |
-H |
以树结构显示信息。 |
-I |
显示附加信息。 |
--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
来标识
因此,系统进程被称为守护进程((Disk And Execution MONitor)
权限¶
执行命令时,用户的凭据将传递给创建的进程。
因此,在默认情况下,进程的实际 UID<code> 和 <code>GID
与 执行命令的用户的 UID
和 GID
相同。
在命令上设置 SUID
(和/或 SGID
)后,实际 UID
(和/或 GID
)将变为命令所有者(和/或所属组)的 UID(和/或 GID),而不再是发出命令的用户或用户组的 UID(和/或 GID)。 因此,有效的 UID 和真实的 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 | 恢复进程 |
19 |
SIGSTOP | 挂起进程 |
信号是进程之间的通信手段。 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
命令¶
job
命令显示后台运行的进程列表,并指定它们的作业编号。
示例:
$ jobs
[1]- Running sleep 1000
[2]+ Running find / > arbo.txt
这些列表示:
- 作业编号
- 进程运行的顺序
+
:未指定作业编号时,fg
和bg
命令默认选择的进程-
:下一个进程选择+
- 正在运行(正在运行的进程)或_已停止_(已挂起的进程)
- 命令
nice
和 renice
命令¶
命令 nice
允许通过指定优先级来执行命令。
nice priority command
示例:
$ nice -n+15 find / -name "file"
与 root
用户不同,标准的普通用户只能降低进程的优先级。 只接受 +0 到 +19 之间的值。
提示
通过修改 /etc/security/limits.conf
文件,可以针对每个用户或每个组取消最后这项限制。
使用 renice
命令可以更改正在运行中的进程优先级。
renice priority [-g GID] [-p PID] [-u UID]
示例:
$ renice +15 -p 1664
-g
| 进程所属组的 GID
。 |
| -p
| 进程的 PID
。 |
| -u
| 进程所有者的 UID
。 |
renice
命令作用于已经运行的进程。 因此,我们可以改变特定进程的优先级,也可以改变属于用户或组的几个进程的优先级。
提示
pidof
命令与 xargs
命令相结合(请参阅 "高级命令" 课程),可允许在单个命令中应用新的优先级:
$ pidof sleep | xargs renice 20
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 [-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 - 已失效的进程("僵尸"),已终止但未被其父进程获取