1362天 Edwiin

还好有你,再见如初。

Linux 进程管理详解

发布于 14天前 / 10 次围观 / 0 条评论 / Linux / Edwiin

进程UnixLinux 系统中对正在运行中应用程序的抽象,通过它可以管理和监视程序对内存、处理器时间和 I / O 资源的使用。

一、进程的组成

一个进程包含内核中的一部分地址空间和一系列数据结构。其中地址空间是内核标记的一部分内存以供进程使用,而数据结构则用来纪录每个进程的具体信息

最主要的进程信息包括:

  • 进程的地址空间图
  • 进程当前的状态( sleeping、stopped、runnable 等)
  • 进程的执行优先级
  • 进程调用的资源信息
  • 进程打开的文件和网络端口信息
  • 进程的信号掩码(指明哪种信号被屏蔽)
  • 进程的属主

PID :进程 ID

每个进程都会从内核获取一个唯一的 ID 值。绝大多数用来操作进程的命令系统调用,都需要用 PID 指定操作的进程对象。

PPID :父进程 ID

UnixLinux 系统中,一个已经存在的进程必须“克隆”它自身来创建一个新的进程。当新的进程克隆后,最初的进程便作为父进程存在。

UID & EUID:真实用户 ID 和有效用户 ID

一个进程的 UID 是其创建者的身份标志(也是对其父进程 UID 的复制)。通常只有进程的创建者和超级用户才有操作该进程的权限
EUID 是一个额外的 UID,用来决定在任意一个特定时间点,一个进程有权限访问的文件和资源。对绝大多数进程而言,UID 和 EUID 是相同的(特殊情况即 setuid)

Niceness

一个进程的计划优先级决定了它能获取到的 CPU 时间。内核有一个动态的算法来计算优先级,同时也会关注一个 Niceness 值,来决定程序运行的优先顺序。

二、信号

信号属于进程级别的中断请求。它们可以作为进程间通信的手段,或者由终端发送以杀死、中断、挂起某个进程。

常见信号列表:

#nameDescriptionDefaultCan catch?Can block?Dump core?
1HUPHangupTerminateYesYesNo
2INTInterrupt(Ctrl + C)TerminateYesYesNo
3QuitQuit(Ctrl + \)TerminateYesYesYes
9KILLKillTerminateNoNoNo
BUSBus errorTerminateYesYesYes 
11SEGVSegmentation faultTerminateYesYesYes
15TERMSoftware terminatationTerminateYesYesNo
STOPStop(Ctrl + Z)StopNoNoNo 
TSTPKeyboard stopStopYesYesNo 
CONTContinue after stopIgnoreYesNoNo 

三、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

$ 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 选项表示使用基于用户信息输出格式

$ 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 选项表示以详细的格式输出进程信息

$ 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 字符显示树状结构,表达程序间的相互关系

$ 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 中的 - 表示逆向排序,即由大到小排序)

$ 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 命令令其在后台继续执行

$ 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​