进程 是 Unix 和 Linux 系统中对正在运行中的应用程序的抽象,通过它可以管理和监视程序对内存、处理器时间和 I / O 资源的使用。
一、进程的组成
一个进程包含内核中的一部分地址空间和一系列数据结构。其中地址空间是内核标记的一部分内存以供进程使用,而数据结构则用来纪录每个进程的具体信息。
最主要的进程信息包括:
- 进程的地址空间图
- 进程当前的状态( sleeping、stopped、runnable 等)
- 进程的执行优先级
- 进程调用的资源信息
- 进程打开的文件和网络端口信息
- 进程的信号掩码(指明哪种信号被屏蔽)
- 进程的属主
PID :进程 ID
每个进程都会从内核获取一个唯一的 ID 值。绝大多数用来操作进程的命令和系统调用,都需要用 PID 指定操作的进程对象。
PPID :父进程 ID
在 Unix 和 Linux 系统中,一个已经存在的进程必须“克隆”它自身来创建一个新的进程。当新的进程克隆后,最初的进程便作为父进程存在。
UID & EUID:真实用户 ID 和有效用户 ID
一个进程的 UID 是其创建者的身份标志(也是对其父进程 UID 的复制)。通常只有进程的创建者和超级用户才有操作该进程的权限。
EUID 是一个额外的 UID,用来决定在任意一个特定时间点,一个进程有权限访问的文件和资源。对绝大多数进程而言,UID 和 EUID 是相同的(特殊情况即 setuid)
Niceness
一个进程的计划优先级决定了它能获取到的 CPU 时间。内核有一个动态的算法来计算优先级,同时也会关注一个 Niceness 值,来决定程序运行的优先顺序。
二、信号
信号属于进程级别的中断请求。它们可以作为进程间通信的手段,或者由终端发送以杀死、中断、挂起某个进程。
常见信号列表:
# | name | Description | Default | Can catch? | Can block? | Dump core? |
---|---|---|---|---|---|---|
1 | HUP | Hangup | Terminate | Yes | Yes | No |
2 | INT | Interrupt(Ctrl + C) | Terminate | Yes | Yes | No |
3 | Quit | Quit(Ctrl + \) | Terminate | Yes | Yes | Yes |
9 | KILL | Kill | Terminate | No | No | No |
BUS | Bus error | Terminate | Yes | Yes | Yes | |
11 | SEGV | Segmentation fault | Terminate | Yes | Yes | Yes |
15 | TERM | Software terminatation | Terminate | Yes | Yes | No |
STOP | Stop(Ctrl + Z) | Stop | No | No | No | |
TSTP | Keyboard stop | Stop | Yes | Yes | No | |
CONT | Continue after stop | Ignore | Yes | No | No |
三、Kill 命令
kill 命令常用来终止某个进程,它可以向进程传递任意信号(默认为 TERM)。kill [-signal] pid
不带任何数字(信号)选项的 kill 命令并不能保证指定进程被杀死,因为 kill 命令默认发送 TERM 信号,而 TERM 是可以被捕获、屏蔽或忽略的。
可以使用 kill -9 pid
命令强制杀死进程(9
代表 KILL 信号,不可被捕获、屏蔽或忽略)。
kill 命令需要指定进程的 PID 号。
pgrep 命令可以通过程序名称(或其他属性如 UID)筛选进程号,pkill 命令可以直接发送指定信号给筛选结果。
如 sudo pkill -u ben
该命令将发送 TERM 信号给所有属于用户 ben 的进程。
killall 命令可以通过程序名称杀死指定进程的所有实例。如:sudo killall apache2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21$ pgrep postgres # 筛选 postgres 进程的 PID 号
25874
25876
25877
25878
25879
25880
25881
$ pgrep -a postgres # 筛选 postgres 进程的 PID 号,并输出详细信息
25874 /usr/lib/postgresql/10/bin/postgres -D /var/lib/postgresql/10/main -c config_file=/etc/postgresql/10/main/postgresql.conf
25876 postgres: 10/main: checkpointer process
25877 postgres: 10/main: writer process
25878 postgres: 10/main: wal writer process
25879 postgres: 10/main: autovacuum launcher process
25880 postgres: 10/main: stats collector process
25881 postgres: 10/main: bgworker: logical replication launcher
$ sudo kill -9 `pgrep postgres` # 杀死 postgres 进程
$ sudo pkill postgres # 同上一条命令
$ sudo killall postgres # 杀死 postgres 进程的所有实例
$ sudo pkill -9 -u postgres # 杀死属于 postgres 用户的所有进程
根据进程 PID 号查找进程可以使用
ps -p <pid> -o comm=
命令
四、进程状态
状态 | 含义 |
---|---|
Runnable | 该进程正在(正准备)执行 |
Sleeping | 该进程正等待某些资源 |
Zombie | 该进程正努力尝试结束 |
Stopped | 该进程已挂起(不允许执行) |
- Runnable 表示进程已经获取到了运行所需的所有资源,只是等待相应的 CPU 时间来处理数据。
- Sleeping 表示进程处于等待特定事件发生的状态。交互式 Shell 和系统守护进程的大部分时间都是 Sleeping 状态,等待用户输入或网络连接。
- Zombies 表示进程已经结束执行,但是还没有收集完所有的状态,在进程表中仍有纪录。
- Stopped 表示进程已停止运行,通常是收到了某种停止信号。
五、PS 命令:监控资源
ps 命令是系统管理员监控进程的主要工具。该命令可以显示进程的 PID、UID、优先级和控制终端,以及进程占用的内存、消耗的 CPU 时间和当前的状态等信息。
常用的 PS 命令选项组合:
1. ps aux
a 选项表示显示所有进程,x 选项表示同时显示没有控制终端的进程(TTY 显示为 ?),u 选项表示使用基于用户的信息输出格式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 225428 9548 ? Ss 7月30 0:30 /lib/systemd/systemd --system --deserialize 19
root 2 0.0 0.0 0 0 ? S 7月30 0:00 [kthreadd]
root 4 0.0 0.0 0 0 ? I< 7月30 0:00 [kworker/0:0H]
root 6 0.0 0.0 0 0 ? I< 7月30 0:00 [mm_percpu_wq]
root 7 0.0 0.0 0 0 ? S 7月30 0:03 [ksoftirqd/0]
root 8 0.0 0.0 0 0 ? I 7月30 14:49 [rcu_sched]
...
starky 6874 0.0 0.1 33016 8556 pts/2 Ss 8月07 0:00 bash
starky 7150 0.0 0.0 33016 6044 pts/2 S+ 8月07 0:00 bash
starky 7151 3.1 16.1 4763784 1227932 pts/2 Sl+ 8月07 272:54 java -Xmx1024M -Xms512M -jar minecraft_server.1.12.2.jar nogui
...
root 18447 0.0 0.0 107984 7116 ? Ss 13:55 0:00 sshd: starky [priv]
starky 18535 0.0 0.0 108092 4268 ? S 13:55 0:00 sshd: starky@pts/1
starky 18536 0.0 0.1 33096 8336 pts/1 Ss 13:55 0:00 -bash
root 18761 0.0 0.0 0 0 ? I 13:55 0:00 [kworker/u8:0]
root 18799 0.0 0.0 0 0 ? I 14:01 0:00 [kworker/u8:1]
root 18805 0.0 0.0 0 0 ? I 14:05 0:00 [kworker/0:2]
starky 18874 0.0 0.0 46780 3568 pts/1 R+ 14:10 0:00 ps -aux
redis 19235 0.2 0.0 58548 3736 ? Ssl 8月04 30:03 /usr/bin/redis-server 127.0.0.1:6379
root 20799 0.0 0.0 107548 7504 ? Ss 8月05 0:00 /usr/sbin/cupsd -l
root 28342 0.0 0.4 535068 36940 ? Ss 8月10 0:16 /usr/sbin/apache2 -k start
其中带中括号的命令(如 [kthreadd])并不是真正的命令而是内核线程。
ps aux
命令输出的各列信息含义如下:
项目 | 解释 |
---|---|
USER | 进程属主的用户名 |
PID | 进程 ID |
%CPU | 进程占用的 CPU 百分比 |
%MEM | 进程使用的内存百分比 |
VSZ | 进程的虚拟大小 |
RSS | 驻留内存大小(内存中的页数) |
TTY | 控制终端 ID |
STAT | 进程当前的状态: R = Runnable D = In uninterruptible sleep S = Sleeping(<20s) T = Traced or stopped Z = Zombie 额外标记: W = Process is swapped out < = 进程有相对于平时更高的优先级 N = 进程有相对于平时更低的优先级 L = Some pages are locked in core s = Process is a session leader |
TIME | 进程已经消耗的 CPU 时间 |
COMMAND | 进程的命令和命令选项 |
2. ps lax
l 选项表示以详细的格式输出进程信息。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26$ ps lax
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
4 0 1 0 20 0 225428 9548 - Ss ? 0:30 /lib/systemd/systemd --system --deserialize 19
1 0 2 0 20 0 0 0 - S ? 0:00 [kthreadd]
1 0 4 2 0 -20 0 0 - I< ? 0:00 [kworker/0:0H]
1 0 6 2 0 -20 0 0 - I< ? 0:00 [mm_percpu_wq]
1 0 7 2 20 0 0 0 - S ? 0:03 [ksoftirqd/0]
1 0 8 2 20 0 0 0 - I ? 14:58 [rcu_sched]
...
0 1000 6874 6871 20 0 33016 8556 wait Ss pts/2 0:00 bash
1 1000 7150 6874 20 0 33016 6044 wait S+ pts/2 0:00 bash
0 1000 7151 7150 20 0 4763784 1227932 futex_ Sl+ pts/2 275:03 java -Xmx1024M -Xms512M -jar minecraft_server.1.12.2.jar nogui
...
4 0 18447 619 20 0 107984 7116 - Ss ? 0:00 sshd: starky [priv]
5 1000 18535 18447 20 0 108092 4268 - S ? 0:00 sshd: starky@pts/1
0 1000 18536 18535 20 0 33096 8336 wait Ss pts/1 0:00 -bash
1 0 19051 2 20 0 0 0 - I ? 0:00 [kworker/3:0]
1 0 19141 2 20 0 0 0 - I ? 0:00 [kworker/2:3]
1 115 19235 1 20 0 58548 3736 - Ssl ? 30:22 /usr/bin/redis-server 127.0.0.1:6379
1 0 19246 2 20 0 0 0 - I ? 0:00 [kworker/2:0]
1 0 19291 2 20 0 0 0 - I ? 0:00 [kworker/u8:0]
1 0 19312 2 20 0 0 0 - I ? 0:00 [kworker/0:2]
1 0 19405 2 20 0 0 0 - I ? 0:00 [kworker/u8:1]
0 1000 19417 18536 20 0 36024 1596 - R+ pts/1 0:00 ps -lax
4 0 20799 1 20 0 107548 7504 - Ss ? 0:00 /usr/sbin/cupsd -l
5 0 28342 1 20 0 535068 36940 - Ss ? 0:16 /usr/sbin/apache2 -k start
ps lax
命令的输出包含了父进程 ID(PPID)、nice 值(NI)还有进程正在等待的资源类型(WCHAN)等。
3. ps axjf
ps axjf
命令能够以树状结构显示各进程间的层级关系
f 选项表示用 ASCII 字符显示树状结构,表达程序间的相互关系。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22$ ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 4 0 0 ? -1 I< 0 0:00 \_ [kworker/0:0H]
2 6 0 0 ? -1 I< 0 0:00 \_ [mm_percpu_wq]
2 7 0 0 ? -1 S 0 0:02 \_ [ksoftirqd/0]
2 8 0 0 ? -1 I 0 4:26 \_ [rcu_sched]
...
1 672 672 672 ? -1 Ss 0 0:00 /usr/sbin/sshd -D
672 27078 27078 27078 ? -1 Ss 0 0:00 \_ sshd: starky [priv]
27078 27166 27078 27078 ? -1 S 1000 0:00 \_ sshd: starky@pts/1
27166 27167 27167 27167 pts/1 27438 Ss 1000 0:00 \_ -bash
27167 27438 27438 27167 pts/1 27438 R+ 1000 0:00 \_ ps axjf
1 681 681 681 ? -1 Ssl 115 9:40 /usr/bin/redis-server 127.0.0.1:6379
1 700 700 700 tty1 700 Ss+ 0 0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
1 710 710 710 ? -1 Ss 0 0:14 /usr/sbin/apache2 -k start
710 25651 710 710 ? -1 S 33 0:00 \_ /usr/sbin/apache2 -k start
710 25652 710 710 ? -1 S 33 0:00 \_ /usr/sbin/apache2 -k start
710 25653 710 710 ? -1 S 33 0:00 \_ /usr/sbin/apache2 -k start
710 25654 710 710 ? -1 S 33 0:00 \_ /usr/sbin/apache2 -k start
710 25655 710 710 ? -1 S 33 0:00 \_ /usr/sbin/apache2 -k start
...
4. ps o
ps o
命令加上选项可以指定信息的输出格式,同时加上 --sort
选项可指定排序依据
如:ps axo pid,ppid,%mem,%cpu,cmd --sort=-%mem
上面的命令表示输出进程的 PID、PPID、内存占用、CPU占用和命令选项。并以内存占用大小排序。(--sort=-%mem
中的 -
表示逆向排序,即由大到小排序)1
2
3
4
5
6
7
8
9
10
11$ ps axo pid,ppid,%mem,%cpu,cmd --sort=-%mem | head
PID PPID %MEM %CPU CMD
1790 1789 14.1 3.8 java -Xmx1024M -Xms512M -jar minecraft_server.1.12.2.jar nogui
1357 1 2.6 0.1 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid
9343 1 2.0 0.0 /usr/bin/python3 /usr/bin/update-manager --no-update --no-focus-on-map
1244 1 1.5 0.0 sogou-qimpanel %U
1024 1 1.0 0.0 /usr/bin/fcitx
1454 1 0.9 0.0 fcitx-qimpanel
7401 1067 0.7 0.0 lxterminal
248 1 0.6 0.0 /lib/systemd/systemd-journald
1119 1 0.6 0.0 nm-applet
可以尝试不同的命令选项组合来获取相应的信息,具体可参考
man ps
六、使用 TOP 命令动态监控进程
top 命令可以实时显示系统当前活跃进程的总体信息及其占用的资源。
top 命令的 -d
选项可以指定信息刷新的时间间隔。同时还有一些常用的交互命令
命令 | 描述 |
---|---|
h | 显示帮助信息 |
k | 终止某个进程 |
i | 忽略闲置和僵死进程(这是一个开关式命令) |
q | 退出 top 程序 |
r | 重新设置某个进程的优先级 |
s | 改变两次刷新之间的延迟时间(单位为s) |
f 或 F | 从当前显示中添加或者删除项目 |
l | 切换显示平均负载和启动时间信息 |
m | 切换显示内存信息 |
t | 切换显示进程和CPU状态信息 |
c | 切换显示命令名称和完整命令 |
M | 根据驻留内存大小进行排序 |
P | 根据CPU使用百分比大小进行排序 |
T | 根据时间/累计时间进行排序 |
w | 将当前设置写入 ~/.toprc 文件中 |
七、前台/后台进程
- 前台进程(也称作交互式进程):由某个终端会话创建和控制的进程。即需要用户控制而不能作为系统服务自动启动。
- 后台进程(也称作非交互式进程):不和终端绑定的进程,不等待用户输入。
可以在命令后带上 & 符号,在后台启用一个 Linux 进程执行该命令。并通过 jobs
命令查看当前的任务。
使用 fg
命令将后台执行的进程调到前台执行
使用 Ctrl + Z
组合键(发送 SIGSTOP 信号)挂起当前进程(前台),并使用 bg
命令令其在后台继续执行1
2
3
4
5
6
7
8
9
10
11
12
13
14$ python -m SimpleHTTPServer & # 后台启动 python 进程
[1] 28036
$ Serving HTTP on 0.0.0.0 port 8000 ...
$ jobs # 使用 jobs 命令查看后台进行的任务
[1]+ 运行中 python -m SimpleHTTPServer &
$ fg %1 # 将后台执行的第一个任务调到前台执行(fg %1)
python -m SimpleHTTPServer
^Z # 使用 Ctrl + Z 组合键(发送 STOP 信号)停止当前进程
[1]+ 已停止 python -m SimpleHTTPServer
$ bg # 使用 bg 命令将进程调至后台继续执行
[1]+ python -m SimpleHTTPServer &
$ fg %1
python -m SimpleHTTPServer
参考资料
UNIX and Linux System Administration Handbook, 4th Edition
All You Need To Know About Processes in Linux