Linux 之旅 15:进程管理

Linux 之旅 15:进程管理

image-20210827141245417

图源:pexels

什么是进程

进程与程序

我们通常所说的程序,是一种静态的可以执行的文件,不同的编程语言开发的程序的表现形式可能是不同的,比如Javascript通常就是以源代码的方式组成的.js文件,或者干脆是直接写在.html页面中。而C或者C++编写的程序则需要在目标机器上编译为机器码(.exe)后才能执行。Java则一般是打包为jar包后进行使用。从易用性角度上来说,我比较喜欢Python,不仅跨平台,而且还有一个方便的包管理软件pip,直接可以下载和更新Pyhon应用。

而进程则是操作系统在从硬盘读取程序的可执行文件后,为程序在内存中申请相应的资源,并让CPU开始执行可执行文件中的指令后的产物。可以看作是"活的程序"。

程序本身是死的,并不会对用户的输入做出响应,也不会产生有价值的输出,只有被操作系统运行,并成为内存中的一个进程才能发挥相应的作用。

进程与程序的关系可以用下图表示:

程式被載入成為程序以及相關資料的示意圖

图源:《鸟哥的私房菜》

相应的,一个程序可以产生若干个进程。

子进程与父进程

在Linux中,进程之间都是有着父子关系的,比如如果A进程启动了B进程,则A就是B的父进程,而B则是A的子进程。并且子进程会继承父进程的环境变量。

在Linu中,对每一个系统中正在运行的进程,都会给予一个进程编号PID,而为了方便管理,系统也会在子进程的相关信息中记录其父进程的PID,命名为PPID(Parent PID)。

子进程和父进程的关系可以用下图表示:

程序相關係之示意圖

图源:《鸟哥的私房菜》

我们可以使用ps -l命令查看当前终端相关的进程:

[icexmoon@xyz ~]$ ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000   1970   1969  0  80   0 - 29252 do_wai pts/0    00:00:00 bash
0 R  1000   2292   1970  0  80   0 - 38331 -      pts/0    00:00:00 ps

可以看到ps这个命令产生的进程PID是2292,其父进程的PID是1970,也就是上边的bash命令产生的进程。所以前者是后者的子进程。

fork and exec

在Linux中,我们往往需要在当前的终端所运行的Bash进程上启动其它程序,事实上就是通过Bash来启动子进程,这种启动子进程的流程被称作fork and exec

之所以这么说,是因为具体的流程是这样的:

  1. 对当前进程进行复制(fork),产生一个新的临时进程
  2. 使用新的临时进程运行程序(exec)

这其中的要点在于,新的临时进程与被fork的进程除了PID不同以外,其余内容,包括临时变量与环境变量都相同。但同时因为新启动的进程是一个独立的进程(虽然是前者的子进程),所以所有的变量或其它部分的操作都不会影响到原有进程。

常驻内存的进程

为了让系统正常运行,需要一些相关的进程常驻内存(比如之前提过的crondatd等),这类进程被我们称为服务(daemon),为了更好地区别服务和普通进程,服务一般会以d字母结尾,比如crondhttpd等。

daemon也被称为守护进程,因为往往这些进程都可以自启动,如果出现异常中止或被用户手动结束,系统可以通过其它方式重新启动。

Linux的多人多任务环境

Bash环境的任务管理

在前边介绍父进程和子进程的时候,那个图示案例是最简单的那类:开启子进程后父进程挂起,直到子进程结束。事实上子进程和父进程是可以同时处于活动状态的,比如:

[icexmoon@xyz ~]$ cp file1 file2 &

通过在命令结尾添加一个&符号,可以让命令变成一个任务(job),然后在后台运行。其实就是让运行这个命令的子进程运行的同时父进程(Bash)依然正常运行,以接受用户输入并做出响应。

关于任务管理(job control)相关内容会在后边介绍。

任务管理

任务管理(job control)是当我们登录系统,并获取Bash Shell后,在单一终端下执行多个任务的操作管理。

什么是任务管理

需要明确的是,这里所说的任务(job),都是在一个终端下通过命令以及&符号创建的同一个Bash进程的子进程,我们不能跨越多个终端进行“任务管理”。

在涉及任务管理的时候,有两个概念需要知道:

  • 前台:有命令提示符的环境被称作前台。实质上就是登录后获取的Bash进程,或者直接将Bash挂起后运行的进程。因为这些情况我们都可以直接通过键盘输入和干预,也可以直观看到输出,所以被称为前台。
  • 后台:通过给命令结尾添加&或者其它方式,将命令在不影响前台Bash进程响应的同时运行或暂停,这种情况下可以认为该命令所处的环境是有别于前台的“后台”。此时我们无法直接通过键盘输入进行干预,需要用到任务管理相关的命令。

任务管理

让命令直接在后台执行

如我们之前所说,如果要让命令在后台执行,最简单的方式就是在结尾加一个&符号:

[root@xyz ~]# tar -zpcf /tmp/etc.tar.gz /etc &
[1] 2871
[root@xyz ~]# tar: 从成员名中删除开头的“/”
[root@xyz ~]# ll -h /tmp/etc.tar.gz
-rw-r--r--. 1 root root 12M 827 15:10 /tmp/etc.tar.gz
[root@xyz ~]# tar -ztf /tmp/etc.tar.gz
etc/
etc/fstab
etc/crypttab
etc/mtab
etc/resolv.conf
etc/fonts/
etc/fonts/conf.d/
... 省略 ...

需要注意的是,虽然此时tar命令是在后台执行,不会影响到我们对前台的操作,但是其正常和错误输出依然是显示在前台的,可能会影响到我们前台的信息查看。所以对于在后台执行的命令,我们往往需要结合重定向操作符使用,比如:

[root@xyz ~]# tar -zpcvf /tmp/etc2.tar.gz /etc > /tmp/etc2.log 2>&1 &
[1] 2867

这样我们就可以通过文件查看输出结果或错误信息了:

[root@xyz ~]# less /tmp/etc2.log

此外,当我们创建一个后台任务后,会出现一个输出[1] 2867,其中[]中的是任务编号,而后边的数字则是PID,在这个例子中,放到后台的tar命令对应的任务编号是1,所属进程的PID则是2867

最后再强调一下,正如之前所说,任务管理部分的功能仅是针对于当前终端,也就是说产生的任务编号同样仅是对当前终端有效,你是不能在另一个终端中使用当前终端产生的任务编号去操作任务的。

将当前任务暂停后丢入后台

在前台执行任务时按下Ctrl+z可以将任务暂停,并丢到后台:

[root@xyz ~]# vim ~/.bashrc
[1]+  已停止               vim ~/.bashrc
[root@xyz ~]# find / -print
... 省略 ...
/proc/746/task/784/fd/1
/proc/746/task/784/fd/2
/proc/746/task/784/fd/3^Z
[2]+  已停止               find / -print

那个+表示是最近操作的任务,已停止是表示任务当前处于暂停状态。

查看后台任务状态

使用jobs命令可以查看后台的任务状态:

[root@xyz ~]# jobs -l
[1]-  3019 停止                  vim ~/.bashrc
[2]+  3020 停止                  find / -print

-l参数可以将任务的PID一同显示出来。

和之前说的一样,+标识的任务是最近操作的后台任务,-标识的是第二近操作的后台任务,其它的后台任务就不会用特殊符号标识,只能通过任务编号去识别和操作。

让后台任务转到前台执行

可以通过fg(foreground)命令让后台命令转移到前台并继续执行:

[root@xyz ~]# jobs -l
[1]-  3019 停止                  vim ~/.bashrc
[2]+  3020 停止                  find / -print
[root@xyz ~]# fg
/proc/1266/task/1266/net/mcfilter
/proc/1266/task/1266/net/rt_cache
/proc/1266/task/1266/net/sockstat
/proc/1266/task/1266/net/udplite6^Z
[2]+  已停止               find / -print

如果不指定任务编号,fg将会操作最近的那个任务(带+的任务)。

当然也可以操作指定编号的任务:

[root@xyz ~]# fg %1
vim ~/.bashrc

[1]+  已停止               vim ~/.bashrc
[root@xyz ~]# jobs -l
[1]+  3019 停止                  vim ~/.bashrc
[2]-  3020 停止                  find / -print

操作后+-标识的任务会发生变化(这是理所当然的)。

此外可以通过fg +fg -这样的方式执行最近和第二近的任务。

让任务在后台继续运行

可以使用bg(background)命令让后台处于暂停状态的任务继续(在后台)运行:

[root@xyz ~]# find / -perm /7000 > /tmp/find.log 2>&1
^Z
[3]+  已停止               find / -perm /7000 > /tmp/find.log 2>&1
[root@xyz ~]# jobs -l
[1]-  3019 停止                  vim ~/.bashrc
[2]   3020 停止                  find / -print
[3]+  9925 停止                  find / -perm /7000 > /tmp/find.log 2>&1
[root@xyz ~]# bg %3;jobs -l
[3]+ find / -perm /7000 > /tmp/find.log 2>&1 &
[1]+  3019 停止                  vim ~/.bashrc
[2]   3020 停止                  find / -print
[3]-  9925 运行中               find / -perm /7000 > /tmp/find.log 2>&1 &

可以看到执行bg %3后,不仅后台编号为3的任务状态变为了运行中,而且所关联的命令结尾多了&符号,这同样表示该命令在后台运行。

结束后台中的任务

有时候我们需要结束后台中的任务,这时候可以使用kill这个命令,事实上这个命令主要用于管理进程,但任务其实也是一个进程,所以同样可以被kill命令终止。

kill命令终止进程的原理是向进程发送一个信号,进程会根据发送的信号类别做出相应的处理。具体包含以下信号:

[root@xyz ~]# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

其中比较重要的有:

  • 1) SIGHUP:重启进程
  • 9) SIGKILL:强制终止进程
  • 15) SIGTERM:正常结束进程

其中kill -9比较常用,如果需要强制结束进程,可以使用。需要注意的是,某些进程如果非正常退出会产生一些异常文件,比如vim,会对再次执行产生一些额外影响。kill -15是正常退出程序,但并不是所有进程都会在接收这个信号后无条件退出,比如vim就会提示你应当使用内部命令q的方式退出。

要终止指定的任务,可以这样:

[root@xyz ~]# jobs -l
[1]+  3019 停止                  vim ~/.bashrc
[2]   3020 停止                  find / -print
[root@xyz ~]# kill -9 %2

[2]   已停止               find / -print
[root@xyz ~]# jobs -l
[1]+  3019 停止                  vim ~/.bashrc
[2]   3020 已杀死               find / -print

kill在处理进程时是直接使用PID的,比如kill -9 3020。处理任务则是使用任务编号,比如kill %2。千万不能混为一谈。

脱机管理问题

正常情况下,我们对Linux主机的使用往往是通过ssh之类的远程工具进行连接的,在这种情况下,如果我们要执行一个耗时比较长的命令,将其放在后台执行,如果断开连接后还会不会运行?

答案是不会,当我们的远程终端断开连接时,Linux主机会检查终端下的后台任务列表(jobs命令输出的部分),并对其中正在运行的命令发出一个hangup信号,之后进程就会处于挂起(Sleep)状态,也就意味着不会继续执行。此外,因为终端所使用的Bash进程会随着终端的断开而结束,所有的任务进程的PPID都会变为1,也就是将变为systemd的子进程。

对于需要脱机后长时间执行的工作,可以使用其它方式执行,比如Linux 之旅 14:任务计划(crontab)中介绍的at命令,这个命令创建的定时任务是和终端无关的,是由atd服务执行的,并不会受到终端断开影响,所以可以用来启动一个需要长时间脱机执行的命令。

此外还可以使用nohup(no hangup)命令。这个命令本身是用来防止命令执行中被挂起的,通过该命令启动的命令在执行中会“免疫”hangup信号,因此我们可以利用它创建一个不会受到终端断开而影响执行的后台任务:

[icexmoon@xyz tmp]$ vim sleep.sh
#!/bin/bash
/bin/sleep 500s
/bin/echo 'already sleeped 500s'
exit 0
[icexmoon@xyz tmp]$ nohup sh /tmp/sleep.sh &
[1] 15862
[icexmoon@xyz tmp]$ nohup: 忽略输入并把输出追加到"nohup.out"

[icexmoon@xyz tmp]$ jobs
[1]+  运行中               nohup sh /tmp/sleep.sh &
[icexmoon@xyz tmp]$ exit

这样做即使断开远程终端,通过nohup启动的后台任务依然将运行。

其实还可以使用其它命令将任务移除后台任务列表,同样可以不再受到hangup信号的影响,具体详情可以阅读Linux job control

进程管理

查看进程

可以使用ps(Process Status)命令查看系统中的进程信息。

查看当前Bash的进程

如果要查看当前终端的Bash产生了哪些进程,可以:

[icexmoon@xyz ~]$ ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  15164  15163  0  80   0 - 29279 do_wai pts/2    00:00:00 bash
0 R  1000  16372  15164  0  80   0 - 38331 -      pts/2    00:00:00 ps

第一个出现的进程就是当前Bash的进程。

输出的信息中各列所代表的含义为:

  • F:进程标识(process flags),4表示此进程权限为root1表示此进程仅执行了fork,没有执行exec
  • S:进程状态:
    • R(Running):运行中或等待运行。
    • S(Interruptible sleep):可被唤醒的睡眠状态。
    • D(Uninterruptible sleep):不可被唤醒的睡眠状态,通常是进程在等待IO。
    • T(Stopped):被任务控制暂停。
    • Z(Zombie):僵尸进程。进程已经结束,但没有被其父进程回收。
  • UID:进程所有者的UID
  • PID:进程编号
  • PPID:父进程编号
  • C:CPU使用率(百分比)
  • PRI:Priority,进程被CPU执行的优先级,数字越小优先级越高。
  • NI:Nice,会影响优先级。
  • ADDR:进程在内存中的地址,如果正在运行,会显示-
  • SZ:进程占用的内存大小。
  • WCHAN:进程是否正在运行,-表示正在运行。
  • TTY:启动进程所用的终端。
  • TIME:运行进程花费的CPU时间。
  • CMD:触发进程的命令。
查看系统的所有进程

如果要查看当前系统中的所有进程,可以:

[icexmoon@xyz ~]$ ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.6 128400  6404 ?        Ss   15:40   0:12 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2  0.0  0.0      0     0 ?        S    15:40   0:00 [kthreadd]
root          4  0.0  0.0      0     0 ?        S<   15:40   0:00 [kworker/0:0H]
root          6  0.0  0.0      0     0 ?        S    15:40   0:08 [ksoftirqd/0]
root          7  0.0  0.0      0     0 ?        S    15:40   0:00 [migration/0]
root          8  0.0  0.0      0     0 ?        S    15:40   0:00 [rcu_bh]
root          9  0.0  0.0      0     0 ?        R    15:40   0:04 [rcu_sched]
root         10  0.0  0.0      0     0 ?        S<   15:40   0:00 [lru-add-drain]
root         11  0.0  0.0      0     0 ?        S    15:40   0:01 [watchdog/0]
root         13  0.0  0.0      0     0 ?        S    15:40   0:00 [kdevtmpfs]
root         14  0.0  0.0      0     0 ?        S<   15:40   0:00 [netns]
...省略...
root      16379  0.1  0.0      0     0 ?        S    20:55   0:01 [kworker/0:2]
root      17352  0.0  0.0      0     0 ?        S    21:11   0:00 [kworker/0:1]
root      17634  0.1  0.0      0     0 ?        S    21:16   0:00 [kworker/0:0]
root      17805  0.1  0.0      0     0 ?        R    21:19   0:00 [kworker/0:3]
root      17831  0.0  0.0      0     0 ?        S    21:20   0:00 [kworker/u256:0]

第一个,PID为1的进程就是systemd,这是Linux系统的主要进程。

这里输出的信息中各列的含义为(和ps -l重复的字段不再一一说明):

  • USER:进程拥有者的用户名
  • %MEM%:进程占用的物理内存百分比
  • VSZ:进程占用的虚拟内存大小(KB)
  • RSS:进程占用的物理内存大小(KB)

除了常用的ps aux方式查看所有进程以外,还可以:

[icexmoon@xyz ~]$ ps -lA
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0      1      0  0  80   0 - 32100 ep_pol ?        00:00:12 systemd
1 S     0      2      0  0  80   0 -     0 kthrea ?        00:00:00 kthreadd
1 S     0      4      2  0  60 -20 -     0 worker ?        00:00:00 kworker/0:0H
1 S     0      6      2  0  80   0 -     0 smpboo ?        00:00:09 ksoftirqd/0
1 S     0      7      2  0 -40   - -     0 smpboo ?        00:00:00 migration/0
...省略...
1 S     0  17634      2  0  80   0 -     0 worker ?        00:00:00 kworker/0:0
1 R     0  17805      2  0  80   0 -     0 ?      ?        00:00:00 kworker/0:3
1 S     0  17831      2  0  80   0 -     0 worker ?        00:00:00 kworker/u256:0
1 S     0  18103      2  0  80   0 -     0 worker ?        00:00:00 kworker/0:1
1 S     0  18272      2  0  80   0 -     0 worker ?        00:00:00 kworker/0:2
0 S     0  18305    849  0  80   0 - 27013 hrtime ?        00:00:00 sleep
0 R  1000  18309  15164  0  80   0 - 38331 -      pts/2    00:00:00 ps

输出的内容与ps aux一样,不过风格与ps -l一致。

此外,还可以通过ps命令列出进程树,以观察进程之间的关系:

[icexmoon@xyz ~]$ 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 S<       0   0:00  \_ [kworker/0:0H]
     2      6      0      0 ?            -1 S        0   0:09  \_ [ksoftirqd/0]
     2      7      0      0 ?            -1 S        0   0:00  \_ [migration/0]
     2      8      0      0 ?            -1 S        0   0:00  \_ [rcu_bh]
     2      9      0      0 ?            -1 R        0   0:04  \_ [rcu_sched]
...省略...
     1   1763   1660   1660 ?            -1 Sl      42   0:00 /usr/libexec/xdg-permission-store
     1   1772   1772   1772 ?            -1 Ssl      0   0:00 /usr/libexec/boltd
     1   1779   1779   1779 ?            -1 Ssl      0   0:01 /usr/libexec/packagekitd
     1   1780   1780   1780 ?            -1 Ss       0   0:00 /usr/sbin/wpa_supplicant -u -f /var/log/wpa_supplicant.log -c /etc/wpa_
     1   1856   1856   1856 ?            -1 Ssl    997   0:00 /usr/libexec/colord

除了查看所有进程,通常我们还需要将psgrep命令结合起来,查找指定的进程:

[icexmoon@xyz ~]$ ps aux | egrep 'cron|rsyslog'
root       1245  0.0  0.4 214432  4296 ?        Ssl  15:41   0:10 /usr/sbin/rsyslogd -n
root       1266  0.0  0.1 126380  1680 ?        Ss   15:41   0:01 /usr/sbin/crond -n
icexmoon  18729  0.0  0.0 112824   988 pts/2    R+   21:35   0:00 grep -E --color=auto cron|rsyslog

因为这里使用了正则高级语法,所以需要使用egrep而非grep命令,或者也可以使用grep -E

动态查看进程变化

ps命令只能一次性展示某一个时刻的进程情况,如果我们需要动态地查看系统中的进程情况(类似Windows的任务管理器),可以使用top命令:

[icexmoon@xyz ~]$ top -d 2
top - 21:38:09 up  5:57,  1 user,  load average: 0.02, 0.05, 0.05
Tasks: 185 total,   3 running, 182 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.5 sy,  0.0 ni, 99.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   995676 total,    82176 free,   553428 used,   360072 buff/cache
KiB Swap:  1048572 total,  1048308 free,      264 used.   247536 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
     1 root      20   0  128400   6404   3564 S  0.0  0.6   0:13.13 systemd
     2 root      20   0       0      0      0 S  0.0  0.0   0:00.02 kthreadd
     4 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H
     6 root      20   0       0      0      0 S  0.0  0.0   0:09.17 ksoftirqd/0
     7 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0
     ... 省略...

-d参数可以执行top输出信息的刷新时间间隔(秒),默认为5秒。按【q】可以退出。

top输出的内容有两部分,上方为整个系统的基本情况,下方为具体进程的相关信息。

基本情况包含的信息有:

  • top

    • 21:38:09 up 5:57:当前时间为21:38:09,本次开机已经运行了5小时57分。
    • 1 user:当前登录系统的有1个用户。
    • load average: 0.02, 0.05, 0.05:CPU在最近的1、5、15分钟内的平均任务负载。
  • tasks

    • 185 total, 3 running, 182 sleeping, 0 stopped, 0 zombie:共有185个进程,3个运行中,182个睡眠中,0个被暂停,0个僵尸进程。
  • %Cpu(s)

    • 0.0 us:用户模式占用的CPU百分比为0%
    • 0.5 sy:系统模式占用的CPU百分比为0.5%
    • 0.0 ni:改变过优先级的用户进程占用CPU的百分比为0%
    • 99.5 id:空闲进程所占CPU的百分比为99.5%
    • 0.0 wa:等待输入、输出的进程占用CPU的百分比
    • 0.0 hi:硬件中断请求服务占用的CPU百分比
    • 0.0 si:软件中断请求服务占用CPU的百分比
    • 0.0 st:(steal time)虚拟时间百分比(在Linux主机上使用虚拟机时)

    如果是多核处理器,可以按下数字键,如【1】切换不同的核心查看单个核心的使用状况。

  • KiB Mem:物理内存的使用情况

    • 995676 total, 82176 free, 553428 used, 360072 buff/cache:总共995676KB,有82176KB空闲,已经使用了553428KB,缓存和缓冲数据占用360072KB。
  • KiB Swap:交换分区(Swap)的使用情况

    • 1048572 total, 1048308 free, 264 used. 247536 avail Mem:总共有1048572KB,有1048308KB处于空闲状态,已使用264KB

    一般来说交换分区最好使用率低于20%为佳,否则说明你的物理内存不够用,需要扩容。

  • 247536 avail Mem:剩余的可用物理内存为247536KB(包含了可以释放并回收的缓存数据占用的空间)

进程部分信息字段与ps中相同,不再赘述。

此外,top命令的输出是默认以CPU占用率进行排序,如果要以内存占用率进行排序,可以按【M】,如果要恢复为CPU占用率排序,可以按【P】。

如果要让top产生瞬时数据,并保存到文件中,可以:

[icexmoon@xyz ~]$ top -b -n 2 > /tmp/top.txt
[icexmoon@xyz ~]$ less /tmp/top.txt

其中-b参数为批量产生数据,会产生瞬时数据,-n表示会输出两次(间隔5秒)。

此外,top也可以监控指定进程:

[icexmoon@xyz ~]$ echo $$
15164
[icexmoon@xyz ~]$ top -d 2 -p 15164
top - 22:22:53 up  6:42,  1 user,  load average: 0.00, 0.01, 0.05
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   995676 total,    82252 free,   553164 used,   360260 buff/cache
KiB Swap:  1048572 total,  1048308 free,      264 used.   247800 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 15164 icexmoon  20   0  117116   3640   1828 S  0.0  0.4   0:00.15 bash

这里$$变量中的值是当前Bash的PID。

通过-p参数可以指定具体的PID进行监控。

top除了可以查看进程信息,也可以执行命令,比如在上一个演示中监控当前Bash进程以后,按下【r】:

top - 22:24:56 up  6:44,  1 user,  load average: 0.00, 0.01, 0.05
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni, 99.5 id,  0.0 wa,  0.0 hi,  0.5 si,  0.0 st
KiB Mem :   995676 total,    82252 free,   553160 used,   360264 buff/cache
KiB Swap:  1048572 total,  1048308 free,      264 used.   247804 avail Mem
PID to renice [default pid = 15164] 
   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 15164 icexmoon  20   0  117116   3640   1828 S  0.0  0.4   0:00.15 bash

会出现提示信息PID to renice [default pid = 15164],按下【Enter】后会出现新的提示信息renice to xxxxx,此时输入10并按下【Enter】,就可以修改Bash进程的nice,此时top再刷新后的信息就会变成:

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 15164 icexmoon  30  10  117116   3640   1828 S  0.0  0.4   0:00.16 bash

可以看到NI的值已经改变,变为了10

pstree

虽然ps可以输出进程树,但是我们有更专业的命令pstree

[icexmoon@xyz ~]$ pstree -up
systemd(1)─┬─ModemManager(781)─┬─{ModemManager}(791)
           │                   └─{ModemManager}(809)
           ├─NetworkManager(930)─┬─{NetworkManager}(936)
           │                     └─{NetworkManager}(940)
           ├─VGAuthService(756)
           ├─abrt-watch-log(754)
           ├─abrt-watch-log(775)
           ├─abrtd(751)
           ├─accounts-daemon(731)─┬─{accounts-daemon}(742)
           │                      └─{accounts-daemon}(817)
           ...省略...
           ├─crond(1266)
           ├─cupsd(1241)
           ├─dbus-daemon(1660,gdm)───{dbus-daemon}(1662)
           ├─dbus-daemon(787,dbus)───{dbus-daemon}(804)
           ├─dbus-launch(1654,gdm)
           ├─dnsmasq(1521,nobody)───dnsmasq(1522,root)

参数-u的作用是输出进程所属的用户,-p则为输出进程的PID。如果子进程与父进程是同一个用户,则用户名不会显示,如果不同才会显示,比如dnsmasq(1521,nobody)───dnsmasq(1522,root)

此外,默认情况下pstree会使用Unicode字符集输出结果,可能会在某些终端中出现连接线乱码的情况,此时可以尝试使用-A参数解决,此参数将强制使用ASCII字符作为连接线进行输出。

进程的管理

之前在介绍结束后台中的任务的时候有提到kill这个命令,kill不单单可以用于结束后台任务,也可以用于结束进程,同样是通过给进程传递一个信号的方式实现,经常会用到以下几种信号:

代号名称内容
1SIGHUP启动被终止的进程,可以让该进程重新读取配置文件,类似重启
2SIGINT相当于使用【Ctrl+c】,中断程序的运行
9SIGKILL强制结束进程
15SIGTERM正常退出程序
19SIGSTOP相当于输入【Ctrl+z】,暂停一个运行中的程序

1、9、15是最为常用的。

kill

之前我们已经展示过如何使用kill命令给任务发送信号,给进程发送信号的方式类似,不过不需要使用%,而是直接指定PID即可,甚至我们还可以结合其它的管道命令使用:

[icexmoon@xyz ~]$ ps aux | grep rsyslogd | grep -v grep | awk '{print $2}'
1246
[icexmoon@xyz ~]$ sudo kill -1 $(ps aux | grep rsyslogd | grep -v grep | awk '{print $2}')
[icexmoon@xyz ~]$ sudo tail -n 5 /var/log/messages
Aug 29 11:27:51 xyz dbus[758]: [system] Successfully activated service 'org.freedesktop.problems'
Aug 29 11:30:02 xyz systemd: Created slice User Slice of root.
Aug 29 11:30:02 xyz systemd: Started Session 2 of user root.
Aug 29 11:30:02 xyz systemd: Removed slice User Slice of root.
Aug 29 11:35:13 xyz rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-55.el7" x-pid="1246" x-info="http://www.rsyslog.com"] rsyslogd was HUPed

/var/log/messages日志中的最后一行可以看出,rsyslogd服务进程已经被重启了。

killall

除了使用kill和PID操作指定的进程,还可以通过killall命令以及命令名称操作相关的所有进程:

[icexmoon@xyz ~]$ sudo killall -1 rsyslogd
[icexmoon@xyz ~]$ sudo tail -n 5 /var/log/messages
Aug 29 11:35:13 xyz rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-55.el7" x-pid="1246" x-info="http://www.rsyslog.com"] rsyslogd was HUPed
Aug 29 11:40:01 xyz systemd: Created slice User Slice of root.
Aug 29 11:40:01 xyz systemd: Started Session 3 of user root.
Aug 29 11:40:01 xyz systemd: Removed slice User Slice of root.
Aug 29 11:40:43 xyz rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-55.el7" x-pid="1246" x-info="http://www.rsyslog.com"] rsyslogd was HUPed
[icexmoon@xyz ~]$ ps aux | grep httpd
icexmoon   2222  0.0  0.0 112824   976 pts/0    R+   11:41   0:00 grep --color=auto httpd
[icexmoon@xyz ~]$ sudo killall -9 httpd
httpd: no process found
[icexmoon@xyz ~]$ sudo killall -i -9 bash
信号 bash(1938) ? (y/N) n
bash: no process found

killall可以一次性操作所有指定命令启动的进程,如果需要在操作时进行类似信号 bash(1938) ? (y/N)的提示,可以使用-i参数。

关于进程的执行顺序

早期的CPU只会顺序执行给它的任务,也就是说必须等到一个程序全部执行完毕才能执行下一个程序,如果是科研项目还好说,如果是个人电脑,体验就极为糟糕了。所以现代操作系统就有了一个称作“CPU调度”的功能,即让CPU在执行任务的最基础单元划分为单条指令(CPU时钟),而将等待CPU执行的任务按CPU时钟进行分配,每个任务按照优先级高低分配不同的CPU时钟,在当前任务执行了所分配的CPU时钟后,无论有无执行完毕,都会执行任务切换,CPU会转而执行另一个任务。

这里边有一个概念就很重要:任务优先级。也就是之前我们所介绍的进程的优先级(Priority),这个值决定了给进程分配的CPU时钟的多少,也就是CPU计算资源的多少,优先级高必然代表着会更快地运行该程序。

Linux中,进程的优先级是由操作系统控制的,用户并不能直接修改,但是用户可以通过修改NI(nice)值来影响优先级,其中Priority与NI的关系是正相关,即NI值越大,Priority也越大(Priority越小优先级越高),NI越小Priority越小。其中NI的值为-20~19,并且除了root可以修改所有进程以外,一般用户只能修改自己进程的NI值,且只能修改为更大的NI值,且不能为负。

nice

可以使用nice命令在命令执行时给与一个初始的NI值:

[root@xyz ~]# nice -n -5 vim &
[1] 3239
[root@xyz ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   3188   3143  0  80   0 - 57992 do_wai pts/0    00:00:00 su
4 S     0   3195   3188  0  80   0 - 29221 do_wai pts/0    00:00:00 bash
4 T     0   3239   3195  0  75  -5 - 36807 do_sig pts/0    00:00:00 vim
0 R     0   3240   3195  0  80   0 - 38331 -      pts/0    00:00:00 ps

[1]+  已停止               nice -n -5 vim
[root@xyz ~]# kill -9 3239

这里vim命令启动的进程NI为-5,PRI是75,优先级明显高于其它进程。

renice

使用renice命令可以修改已经存在的进程的NI值:

[root@xyz ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   3188   3143  0  80   0 - 57992 do_wai pts/0    00:00:00 su
4 S     0   3195   3188  0  80   0 - 29272 do_wai pts/0    00:00:00 bash
0 R     0   3283   3195  0  80   0 - 38331 -      pts/0    00:00:00 ps
[root@xyz ~]# renice -n -5 3195
3195 (进程 ID) 旧优先级为 0,新优先级为 -5
[root@xyz ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   3188   3143  0  80   0 - 57992 do_wai pts/0    00:00:00 su
4 S     0   3195   3188  0  75  -5 - 29272 do_wai pts/0    00:00:00 bash
0 R     0   3309   3195  0  75  -5 - 38331 -      pts/0    00:00:00 ps

可以看到命令bash所在的进程优先级被修改了。

此外需要注意的是ps命令触发的进程的优先级也改变了,和bash进程的优先级一样,这是因为ps命令触发的进程是bash所在进程的子进程,而子进程会继承父进程的优先级。

查看系统资源信息

除了pstop命令外,还有一些其它命令可以查看系统的相关资源的情况。

free

free命令可以用于查看系统内存的使用情况:

[root@xyz ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:            972         489         110          10         372         318
Swap:          1023           0        1023
[root@xyz ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           972M        489M        110M         10M        372M        318M
Swap:          1.0G          0B        1.0G

free可以输出物理内存和交换分区的使用情况,且可以指定输出数据的单位,比如-m就是指输出的数据单位是MB,也可以指定-b-k-g等。也可以指定-h,和df命令类似。

uname

使用uname命令可以查看系统内核的相关信息:

[root@xyz ~]# uname -a
Linux xyz.icexmoon.centos 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

使用-a参数可以输出系统所有的信息,包括:

  • Linux:内核名称
  • xyz.icexmoon.centos:主机名
  • 3.10.0-1160.el7.x86_64:内核版本
  • SMP Mon Oct 19 16:18:59 UTC 2020:内核版本构建时间
  • x86_64:硬件架构平台
uptime

uptime用于查看系统启动时间与任务负载:

[root@xyz ~]# uptime
 16:11:35 up  1:53,  1 user,  load average: 0.00, 0.02, 0.05

输出的信息表示:当前时间为16:11:35,已经运行了1小时53分,目前有1个登录用户,最近1、5、15分钟平均任务负载为0.000.020.05

netstat

netstat可以用于追踪网络和socket文件,常用于网络监控:

[root@xyz ~]# netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0     36 192.168.1.105:ssh       icexmoon-book:8772      ESTABLISHED
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ]         DGRAM                    14024    /run/systemd/shutdownd
unix  3      [ ]         DGRAM                    9195     /run/systemd/notify
unix  2      [ ]         DGRAM                    9197     /run/systemd/cgroups-agent
unix  5      [ ]         DGRAM                    9208     /run/systemd/journal/socket
...省略...
unix  2      [ ]         DGRAM                    30055
unix  3      [ ]         STREAM     CONNECTED     33286    /run/dbus/system_bus_socket
unix  3      [ ]         STREAM     CONNECTED     33246
unix  2      [ ]         DGRAM                    50178
unix  3      [ ]         STREAM     CONNECTED     32969    /run/systemd/journal/stdout
unix  3      [ ]         STREAM     CONNECTED     33063    @/tmp/dbus-DRD7qNZ0s2
unix  3      [ ]         STREAM     CONNECTED     30489
unix  3      [ ]         STREAM     CONNECTED     30474
unix  3      [ ]         STREAM     CONNECTED     21389
unix  3      [ ]         STREAM     CONNECTED     33453    @/tmp/dbus-y72WF93R
unix  3      [ ]         STREAM     CONNECTED     30751    @/tmp/dbus-DRD7qNZ0s2
unix  3      [ ]         STREAM     CONNECTED     30456

netstat输出的信息分为两部分,上边是本地LInux主机和外部的网络连接,下边是本机内互相之间进行通信进程。

第一部分相关的字段有:

  • Proto:网络协议,分为TCP和UDP
  • Recv-Q:接收的数据量(非用户进程)
  • Send-Q:发送的数据量(非用户进程)
  • Local Address:本地IP和端口
  • Foreign Address:远程IP和端口
  • State:连接状态,主要有ESTABLISHED(建立连接)和LISTEN(监听)。

第二部分是本机内互相通信的进程,它们是通过 socket 文件实现的互相通信,具体的字段有:

  • Proto:协议,一般为Unix
  • RefCnt:连接到此Socket的进程数量
  • Flags:连接标识
  • Type:socket存取的类型,主要有STREAM和不需要确认的DGRAM两种(关系应该类似于TCP和UDP)。
  • State:若为CONNECTED则表示多个进程之间的连系已建立。
  • Path:连接到此Socket的相关进程的路径或相关数据的输出路径

有时候我们需要查看Linux主机上已经启动的正在监听端口的Web服务:

[root@xyz ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1577/master
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      739/rpcbind
tcp        0      0 192.168.122.1:53        0.0.0.0:*               LISTEN      1483/dnsmasq
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1241/sshd
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1243/cupsd
tcp6       0      0 ::1:25                  :::*                    LISTEN      1577/master
tcp6       0      0 :::111                  :::*                    LISTEN      739/rpcbind
...省略...

这几个参数的含义为:

  • t:显示TCP连接
  • u:显示UDP连接
  • l:显示正在监听的连接
  • n:显示端口(port number)
  • p:显示PID
dmesg

系统内核在启动和运行中,都会往内存中的受保护区域写入一些信息,dmesg可以读取并输出这些信息:

[root@xyz ~]# dmesg | less
[root@xyz ~]# dmesg | grep sda
[    9.181946] sd 0:0:0:0: [sda] 83886080 512-byte logical blocks: (42.9 GB/40.0 GiB)
[    9.182083] sd 0:0:0:0: [sda] Write Protect is off
[    9.182087] sd 0:0:0:0: [sda] Mode Sense: 61 00 00 00
[    9.182424] sd 0:0:0:0: [sda] Cache data unavailable
[    9.182427] sd 0:0:0:0: [sda] Assuming drive cache: write through
[    9.470809]  sda: sda1 sda2 sda3 sda4 sda5 sda6 sda7 sda8 sda9
[    9.472461] sd 0:0:0:0: [sda] Attached SCSI disk
[   19.067050] XFS (sda4): Mounting V5 Filesystem
[   19.068455] XFS (sda2): Mounting V5 Filesystem
[   19.241047] XFS (sda4): Ending clean mount
[   20.607481] XFS (sda2): Ending clean mount
vmstat

vmstat可以动态地报告内存、交换分区、CPU、I/O等的使用情况:

[root@xyz ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 112332   1080 381468    0    0    48     5   53  105  0  0 99  0  0

默认输出的是瞬时值,如果要每隔5秒报告一次,可以:

[root@xyz ~]# vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 111960   1080 381500    0    0    48     5   53  104  0  0 99  0  0
 0  0      0 111960   1080 381500    0    0     0    18   54   91  0  0 100  0  0
 0  0      0 111960   1080 381500    0    0     0     0   46   82  0  0 100  0  0

会一直输出,直到使用Ctrl+c终止。

也可以每隔1秒报告3次:

[root@xyz ~]# vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 112084   1080 381504    0    0    48     5   53  104  0  0 99  0  0
 0  0      0 112084   1080 381504    0    0     0     0   41   76  0  0 100  0  0
 1  0      0 112084   1080 381504    0    0     0     0   41   72  0  1 99  0  0

其中各字段的含义为:

  • procs:进程

    • r:等待运行的进程数量
    • b:不能被唤醒的进程数量(等待I/O结果)

    这两个值如果比较大表明系统的负载较高。

  • memory:物理内存

    • swpd:使用的虚拟内存的容量
    • free:空闲容量
    • buff:缓冲容量
    • cache:缓存容量
  • swap:交换分区

    • si:从磁盘交换到内存的交换页数量,单位:KB/秒
    • so:从内存交换到磁盘的交换页数量,单位:KB/秒

    这两个值越大,表明系统在频繁地交换分页文件,是物理内存不够用地表现。

  • io

    • bi:从磁盘读入的区块数量,单位:块/秒
    • bo:写入磁盘的区块数量,单位:块/秒

    这两个值越大表明系统在进行忙碌的I/O操作。

  • system

    • in:每秒的中断数,包括时钟中断
    • cs:每秒的环境(上下文)切换次数
  • CPU:以CPU总使用时间的百分比显示

    • us:非内核层的CPU使用时间
    • sy:内核的CPU使用时间
    • id:空闲时间
    • wa:等待I/O所花费的时间
    • st:被虚拟机所使用的时间

此外,vmstat也可以更进一步查看某个部分更详细的使用情况,比如查看磁盘:

[root@xyz ~]# vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
       total merged sectors      ms  total merged sectors      ms    cur    sec
sda    12126     34  798793   20318   2472    435   85113   12579      0     18
sr0        0      0       0       0      0      0       0       0      0      0
dm-0   10255      0  729805   18813   2838      0   72205   15725      0     17
dm-1      88      0    4408      46      0      0       0       0      0      0
dm-2     216      0   10326     354     61      0    4716     150      0      0

特殊文件与进程

具有SUID/SGID权限的命令的执行状态

之前在介绍目录和文件的权限管理时有提到过SUID和SGID,现在介绍了进程后,我们可以直接观察进程树:

[icexmoon@xyz ~]$ passwd
更改用户 icexmoon 的密码 。
为 icexmoon 更改 STRESS 密码。
(当前)UNIX 密码:#按下【Ctrl+z】后输入【Enter】

[1]+  已停止               passwd
[icexmoon@xyz ~]$ pstree -uA
systemd-+-ModemManager---2*[{ModemManager}]
        |-NetworkManager---2*[{NetworkManager}]
        |-VGAuthService
        |-2*[abrt-watch-log]
        ...省略...
        |-sshd---sshd---sshd(icexmoon)---bash-+-passwd(root)
        |                                     `-pstree
		...省略...

可以看到,因为passwd具有SUID的权限,所以在被bash启动后其拥有者从当前用户icexmoon变为了passwd这个可执行文件的拥有者root

/proc/*代表的意义

之前我们有说过/proc目录其实是内存的映射,事实上内存中的进程以PID的形式存在于这个目录中:

[icexmoon@xyz ~]$ ll /proc | head -n 10
总用量 0
dr-xr-xr-x.  9 root           root                         0 829 11:26 1
dr-xr-xr-x.  9 root           root                         0 829 11:26 10
dr-xr-xr-x.  9 root           root                         0 829 11:26 11
dr-xr-xr-x.  9 root           root                         0 829 11:27 1241
dr-xr-xr-x.  9 root           root                         0 829 11:27 1242
dr-xr-xr-x.  9 root           root                         0 829 11:27 1243
dr-xr-xr-x.  9 root           root                         0 829 11:27 1246
dr-xr-xr-x.  9 root           root                         0 829 11:27 1260
dr-xr-xr-x.  9 root           root                         0 829 11:27 1272

其中/proc/1这个目录就代表的是PID为1的进程,即systemd

[icexmoon@xyz ~]$ sudo ls -al /proc/1
总用量 0
dr-xr-xr-x.   9 root root 0 829 11:26 .
dr-xr-xr-x. 200 root root 0 829 11:26 ..
dr-xr-xr-x.   2 root root 0 829 16:29 attr
-rw-r--r--.   1 root root 0 829 17:09 autogroup
-r--------.   1 root root 0 829 17:09 auxv
-r--r--r--.   1 root root 0 829 11:26 cgroup
--w-------.   1 root root 0 829 17:09 clear_refs
-r--r--r--.   1 root root 0 829 11:26 cmdline
-rw-r--r--.   1 root root 0 829 11:26 comm
-rw-r--r--.   1 root root 0 829 17:09 coredump_filter
-r--r--r--.   1 root root 0 829 17:09 cpuset
...省略...

其中cmdline这个文件表示触发进程的命令行:

[icexmoon@xyz ~]$ sudo cat /proc/1/cmdline
/usr/lib/systemd/systemd--switched-root--system--deserialize22

environ这个文件表示进程的环境变量。

对于整个Linux系统,相关的内容由以下文件构成:

文件内容
/proc/cmdline加载内核时执行的命令行
/proc/cpuinfo本机的CPU相关信息
/proc/devices系统各个主要设备的代号
/proc/filesystems目前已加载的文件系统
/proc/interrupts系统上的IRQ分配状态
/proc/ioports各设备配置的I/0端口
/proc/kcore内存
/proc/loadavgCPU的平均任务负载
/proc/meminfo内存使用情况
/proc/modules已加载的模块(驱动)
/proc/mounts已挂载的文件系统
/proc/swaps交换分区
/proc/partitions硬盘分区
/proc/uptime系统运行情况
/proc/version内核版本
/proc/bus/*总线设备(包括USB设备等)

文件关联

使用Windows稍微久点的同学肯定遇到过删除一个文件的时候提示该文件被某某进程占用,无法删除的情况。所以文件和进程是由关联性的,我们有时候需要找出某个进程正在使用的文件,或者某个文件正在被哪些进程使用。

fuser

fuser(file user)可以根据文件找出正在使用该文件的进程:

[icexmoon@xyz ~]$ fuser -uv .
                     用户     进程号 权限   命令
/home/icexmoon:      icexmoon   3143 ..c.. (icexmoon)bash

这里使用fuser输出了当前使用~icexmoon目录的相关进程。

参数-u会同时显示进程的拥有者,-v会显示进程和文件的完整相关性。

其中..c..表示进程和文件的关联性,有这些可能的值:

  • c:当前目录(非子目录)
  • e:可被触发为执行状态
  • f:被开启的文件
  • r:顶层目录(root derectory)
  • F:该文件被其它程序占用了,在等待响应中
  • m:动态函数库(dll)

使用-m参数可以查看某个目录所在的文件系统所关联的进程:

[root@xyz ~]# fuser -uv /proc
                     用户     进程号 权限   命令
/proc:               root     kernel mount (root)/proc
                     rtkit       756 .rc.. (rtkit)rtkit-daemon
[root@xyz ~]# fuser -muv /proc
                     用户     进程号 权限   命令
/proc:               root     kernel mount (root)/proc
                     root          1 f.... (root)systemd
                     root        491 f.... (root)systemd-journal
                     root        744 f.... (root)udisksd
                     rtkit       756 .rc.. (rtkit)rtkit-daemon
                     root        931 f.... (root)NetworkManager
                     root       1260 F.... (root)libvirtd
                     root       1307 F.... (root)X
                     gdm        1702 f.... (gdm)gnome-shell
                     root       1782 f.... (root)packagekitd

这对umount时无法卸载很有用:

[root@xyz home]# cd ~
[root@xyz ~]# pwd
/root
[root@xyz ~]# umount /home
umount: /home:目标忙。
        (有些情况下通过 lsof(8) 或 fuser(1) 可以
         找到有关使用该设备的进程的有用信息)
[root@xyz ~]# fuser -muv /home
                     用户     进程号 权限   命令
/home:               root     kernel mount (root)/home
                     icexmoon   3143 ..c.. (icexmoon)bash
                     root       4060 ..c.. (root)passwd

可以清楚地看到,是有3个相关进程正在使用该文件系统,需要关闭bashpasswd两个进程后才可以卸载/home这个文件系统,具体可以通过手动关闭进程,或者使用kill命令。此外还可以:

[root@xyz ~]# fuser -mki /home
/home:                3143c  4060c  5031c
杀死进程 3143 ? (y/N) n
杀死进程 4060 ? (y/N) n
杀死进程 5031 ? (y/N) n

像上面展示地那样,使用-k参数可以直接关闭相关联的进程(安全起见应该同时使用-i参数)。

fuser可以查看目录和文件系统关联的进程,当然也可以查看一个文件关联的进程:

[root@xyz ~]# find /run -type p
/run/dmeventd-client
/run/dmeventd-server
/run/systemd/inhibit/7.ref
/run/systemd/inhibit/6.ref
/run/systemd/inhibit/5.ref
/run/systemd/inhibit/4.ref
/run/systemd/inhibit/2.ref
/run/systemd/inhibit/1.ref
/run/systemd/sessions/31.ref
/run/systemd/sessions/13.ref
/run/systemd/sessions/c1.ref
/run/systemd/initctl/fifo
[root@xyz ~]# fuser -uv /run/systemd/sessions/c1.ref
                     用户     进程号 权限   命令
/run/systemd/sessions/c1.ref:
                     root        785 f.... (root)systemd-logind
                     root       1445 F.... (root)gdm-session-wor
lsof

lsof(list open files)可以列出被进程所使用的文件名称:

[root@xyz ~]# lsof | head -n 10
COMMAND    PID  TID           USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
systemd      1                root  cwd       DIR              253,0       236         64 /
systemd      1                root  rtd       DIR              253,0       236         64 /
systemd      1                root  txt       REG              253,0   1632776   25931100 /usr/lib/systemd/systemd
systemd      1                root  mem       REG              253,0     20064    8673004 /usr/lib64/libuuid.so.1.3.0
systemd      1                root  mem       REG              253,0    265576    9453934 /usr/lib64/libblkid.so.1.1.0
systemd      1                root  mem       REG              253,0     90248    8673000 /usr/lib64/libz.so.1.2.7
systemd      1                root  mem       REG              253,0    157424    8673022 /usr/lib64/liblzma.so.5.2.2
systemd      1                root  mem       REG              253,0     23968    8673015 /usr/lib64/libcap-ng.so.0.0.0
systemd      1                root  mem       REG              253,0     19896    8693416 /usr/lib64/libattr.so.1.1.0

默认将输出所有使用文件的进程。如果仅要列出root所属的使用socket文件的进程:

[root@xyz ~]# lsof -u root -a -U
COMMAND    PID USER   FD   TYPE             DEVICE SIZE/OFF  NODE NAME
systemd      1 root   12u  unix 0xffff99943fbea200      0t0 13919 /run/systemd/private
systemd      1 root   13u  unix 0xffff99941d449dc0      0t0 31103 /run/systemd/journal/stdout
systemd      1 root   15u  unix 0xffff99941d44b300      0t0 31104 /run/systemd/journal/stdout
systemd      1 root   16u  unix 0xffff999417239540      0t0 32172 /run/systemd/journal/stdout
systemd      1 root   17u  unix 0xffff999417239dc0      0t0 32173 /run/systemd/journal/stdout
systemd      1 root   18u  unix 0xffff99941723e1c0      0t0 32203 /run/systemd/journal/stdout
systemd      1 root   20u  unix 0xffff99943fbebfc0      0t0 13997 /run/lvm/lvmpolld.socket
...省略...

其中参数-u用于指定进程的所属用户,-U参数是指定使用了UNIX socket file的进程,-a参数是可以让输出的结果必须要同时满足所有的参数条件(相当于and,默认情况下各参数之间的关系是or)。

如果要查看系统上所有被使用的外接设备:

[root@xyz ~]# lsof +d /dev | head -n 10
COMMAND    PID           USER   FD   TYPE             DEVICE SIZE/OFF  NODE NAME
systemd      1           root    0u   CHR                1,3      0t0  6513 /dev/null
systemd      1           root    1u   CHR                1,3      0t0  6513 /dev/null
systemd      1           root    2u   CHR                1,3      0t0  6513 /dev/null
systemd      1           root   30u  unix 0xffff99943fbe9980      0t0  9210 /dev/log
systemd      1           root   34r   CHR             10,235      0t0  8682 /dev/autofs
kdevtmpfs   13           root  cwd    DIR                0,5     3480     3 /dev
kdevtmpfs   13           root  rtd    DIR                0,5     3480     3 /dev
systemd-j  491           root    0r   CHR                1,3      0t0  6513 /dev/null
systemd-j  491           root    1w   CHR                1,3      0t0  6513 /dev/null

-d参数用于输出顶级目录的结果,不会降目录。

如果要查找root用户下bash相关的进程:

[root@xyz ~]# lsof -u root | grep bash
ksmtuned   863 root  txt       REG              253,0    964536      34262 /usr/bin/bash
bash      4439 root  cwd       DIR              253,0       254   25165889 /root
bash      4439 root  rtd       DIR              253,0       236         64 /
bash      4439 root  txt       REG              253,0    964536      34262 /usr/bin/bash
...省略...
pidof

pidof命令的用途很简单,就是获取指定命令的PID:

[root@xyz ~]# pidof systemd rsyslogd
1 1246
[root@xyz ~]# pidof bash
5091 5031 4439 3143 863

这个命令可以结合其它命令一起使用。

关于进程管理的内容就介绍到这里,谢谢阅读。

参考资料

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Re: 《Linux 进程管理命令》   ---------------------------------------内容提要: 01/15)命令 ps         :查看进程(快照)02/15)命令 pstree   :显示进程状态树03/15)命令 pgrep   :查找匹配条件的进程04/15)命令 kill        :终止进程号(1277)05/15)命令 killall    :通过进程名(nginx)终止进程(父/子进程)06/15)命令 pkill      :通过进程名终止进程(通杀)/终止客户端(pst/tty)07/15)命令 top       :实时显示系统中各个进程的资源占用状况(录像)08/15)命令 nice      :调整程序运行时的优先级09/15)命令 renice   :调整运行中的进程的优先级10/15)命令 nohup  :用户退出系统,进程继续工作11/15)命令 strace   :跟踪进程的系统调用12/15)命令 ltrace    :跟踪进程调用库函数13/15)命令 runlevel:输出当前运行级别14/15)命令 init        :初始化 Linux 进程15/15)命令 service  :管理系统服务  本人在教学和实战过程中发现,即便是有一定运维经验的人,可能已经能够搭建一定复杂度的Linux架构,但是在来来回回的具体操作中,还是体现出CLI(命令界面)功底不够扎实,甚至操作的非常‘拙’、处处露‘怯’。 对一个士兵来说,枪就是他的武器,对于一个程序员来说,各种library(工具库)就是他的武器;而对于Linux运维人员来说,无疑命令行工具CLI(命令界面)就是他们的武器;高手和小白之间的差距往往就体现在对于这些“武器”的掌握和熟练程度上。有时候一个参数就能够解决的事情,小白们可能要写一个复杂的Shell脚本才能搞定,这就是对CLI(命令界面)没有理解参悟透彻导致。 研磨每一个命令就是擦拭手中的作战武器,平时不保养不理解,等到作战的时候,一定不能够将手中的武器发挥到最好,所以我们要平心、静气和专注,甘坐冷板凳一段时间,才能练就一身非凡的内功! 本教程从实战出发,结合当下流行或最新的Linux(v6/7/8 版本)同时演示,将命令行结合到解决企业实战问题中来,体现出教学注重实战的务实精神,希望从事或未来从事运维的同学,能够认真仔细的学完Linux核心命令的整套课程。 本课程系列将逐步推出,看看我教学的进度和您学习的步伐,孰占鳌头! 注:关于教学环境搭建,可以参考本人其它课程系列,本教学中就不再赘述! 《参透 VMware 桌面级虚拟化》 《在虚拟机中安装模版机(包括应用软件等)》 《SecureCRT 连接 GNS3/Linux 的安全精密工具》

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值