进程是程序的运行实例(running instance)。运行在计算机中的多个进程都被分配了一个称为进程 ID(PID)的唯一标识数字。同一个程序的多个实例可以同时运行,但是它们各自拥有不同PID和属性。进程属性包括拥有该进程的用户、进程使用的内存数量、进程占用的CPU时间等。这则攻略展示了如何收集进程的相关信息。
10.2.1 预备知识
和进程管理相关的重要命令是top、ps和pgrep。这些命令在所有的Linux发行版中都可以找到。
10.2.2 实战演练
ps可以报告活跃进程的相关信息。这些信息包括:拥有进程的用户、进程的起始时间、进程
对应的命令路径、PID、进程所属的终端(TTY)、进程使用的内存、进程占用的CPU等。例如:
$ psPID TTY TIME CMD1220 pts/0 00:00:00 bash1242 pts/0 00:00:00 ps
ps命令默认只显示从当前终端所启动的进程。第一列是PID,第二列是TTY,第三列是进程的运行时长,最后一列是CMD(进程所对应的命令)。
可以使用命令行参数来修改ps命令的输出。
ps命令默认只显示从当前终端所启动的进程。第一列是PID,第二列是TTY,第三列是进程的运行时长,最后一列是CMD(进程所对应的命令)。
可以使用命令行参数来修改ps命令的输出。
选项-f(full)可以显示多列信息:
$ ps -fUID PID PPID C STIME TTY TIME CMDslynux 1220 1219 0 18:18 pts/0 00:00:00 -bashslynux 1587 1220 0 18:59 pts/0 00:00:00 ps -f
[root@dev workspace]# ps -fUID PID PPID C STIME TTY TIME CMDroot 9 8 0 19:24 pts/0 00:00:00 -bashroot 25 9 0 19:31 pts/0 00:00:00 ps -f[root@dev workspace]#
选项-e(every)和-ax(all)能够输出系统中运行的所有进程信息。
选项
-x(配合-a)可以解除ps默认设置的TTY限制。通常如果使用不带参数的ps命令,只能打印出属于当前终端的进程。
命令ps -e、ps -ef、ps -ax以及ps -axf都能够生成包含所有进程的报告,提供比ps更多的信息:
$ ps -e | head -5PID TTY TIME CMD1 ? 00:00:00 init2 ? 00:00:00 kthreadd3 ? 00:00:00 migration/04 ? 00:00:00 ksoftirqd/0
[root@dev workspace]# ps -e | head -5PID TTY TIME CMD1 ? 00:00:00 init7 ? 00:00:00 init8 ? 00:00:00 init9 pts/0 00:00:00 bash[root@dev workspace]# ps -e | tail -57 ? 00:00:00 init8 ? 00:00:00 init9 pts/0 00:00:00 bash28 pts/0 00:00:00 ps29 pts/0 00:00:00 bash[root@dev workspace]# ps -e | headPID TTY TIME CMD1 ? 00:00:00 init7 ? 00:00:00 init8 ? 00:00:00 init9 pts/0 00:00:00 bash30 pts/0 00:00:00 ps31 pts/0 00:00:00 head[root@dev workspace]# ps -ef | headUID PID PPID C STIME TTY TIME CMDroot 1 0 0 19:24 ? 00:00:00 /initroot 7 1 0 19:24 ? 00:00:00 /initroot 8 7 0 19:24 ? 00:00:00 /initroot 9 8 0 19:24 pts/0 00:00:00 -bashroot 32 9 0 19:46 pts/0 00:00:00 ps -efroot 33 9 0 19:46 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=head /usr/bin/head[root@dev workspace]# ps -axPID TTY STAT TIME COMMAND1 ? Sl 0:00 /init7 ? Ss 0:00 /init8 ? S 0:00 /init9 pts/0 Ss 0:00 -bash34 pts/0 R+ 0:00 ps -ax[root@dev workspace]#
选项-e产生的输出内容很多。我们使用head进行了过滤,只列出了其中的前5项。
选项-o PARAMETER1,PARAMETER2可以指定显示哪些数据。
-o的参数以逗号(,)作为分隔符。逗号与接下来的参数之间是没有空格的。选项-o可以和选项-e配合使用(-oe)来列出系统中运行的所有进程。但如果在-o中需要使用过滤器,例如列出特定用户拥有的进程,那就不能再搭配-e了。因为-e和过滤器结合使用没有任何实际效果,依旧会显示所有的进程。
在下面的例子中,comm代表COMMAND,pcpu代表CPU占用率:
$ ps -eo comm,pcpu | head -5COMMAND %CPUinit 0.0init 0.0init 0.0bash 0.0ps 0.0head 0.0
10.2.3 工作原理
选项-o可以使用不同的参数,这些参数及其描述如表10-1所示。
表 10-1
| 参 数 | 描 述 |
|---|---|
pcpu |
CPU 占用率 |
pid |
进程 ID |
ppid |
父进程 ID |
comm |
可执行文件名 |
cmd |
简单命令 |
user |
启动进程的用户 |
nice |
优先级 |
time |
累计的CPU时间 |
etime |
进程启动后运行的时长 |
tty |
所关联的TTY设备 |
euid |
有效用户ID |
stat |
进程状态 |
[root@dev workspace]# ps -eo comm,pid,pcpu,ppid,cmd,user,nice,time,etime,tty,euid,statCOMMAND PID %CPU PPID CMD USER NI TIME ELAPSED TT EUID STATinit 1 0.0 0 /init root 0 00:00:00 35:18 ? 0 Slinit 7 0.0 1 /init root 0 00:00:00 35:17 ? 0 Ssinit 8 0.0 7 /init root 0 00:00:00 35:17 ? 0 Sbash 9 0.0 8 -bash root 0 00:00:00 35:17 pts/0 0 Ssps 45 0.0 9 ps -eo comm,pid,pcpu,ppid,c root 0 00:00:00 00:00 pts/0
10.2.4 补充内容
ps可以配合grep以及其他工具生成定制的报告。
显示进程的环境变量
有些进程依赖于所定义的环境变量。了解这些环境变量及其取值有助于调试或定制进程。
ps命令通常并不会显示进程的环境信息。输出修饰符e可以将其添加到命令尾部:
$ ps e
简单命令是我们平时使用最频繁的一类命令。它是由空白字符分隔的一系列单词,以
shell控制操作符作为结尾。第一个单词指定要执行的命令,余下的单词作为命令参数。shell控制操作符可以是换行符,或者是||、&&、&、;、;;、|、|&、(、)。详情可参阅 Bash Reference Manual,3.2.1节。
请看下面的例子:
$ ps -eo pid,cmd e | tail -n 11238 -bash USER=slynux LOGNAME=slynux HOME=/home/slynuxPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binMAIL=/var/mail/slynux SHELL=/bin/bash SSH_CLIENT=10.211.55.2 49277 22SSH_CONNECTION=10.211.55.2 49277 10.211.55.4 22 SSH_TTY=/dev/pts/0
环境信息可以帮助跟踪apt-get包管理器在使用过程中出现的问题。如果你是通过HTTP代理连接到Internet,你也许需要使用http_proxy=host:port来设置环境变量。如果没有设置的话,apt-get会无法找到代理服务器,进而返回错误信息。只要知道了是没有设置http_proxy,问题就好解决了。
当使用如cron(本章随后会介绍)这类调度工具运行应用程序时,有可能忘了设置所需的环境变量。下面的crontab条目就无法打开基于GUI窗口的应用:
00 10 * * * /usr/bin/windowapp
因为GUI应用需要使用环境变量DISPLAY。要想确定都需要哪些环境变量,可以先手动运行windowapp,然后使用命令ps -C windowapp -eo cmd e。
确定了所需的环境变量之后,将其定义在crontab中的命令之前:
00 10 * * * DISPLAY=:0 /usr/bin/windowapp
或者
DISPLAY=:000 10 * * * /usr/bin/windowapp
环境变量定义DISPLAY=:0是从ps命令的输出中得到的。
创建进程树状视图
ps命令能够输出进程的PID,但是从子进程一直跟踪到最终的父进程是一件非常枯燥的事。在ps命令的尾部加上f就可以创建进程的树状视图,显示出任务之间的父子关系。下面的例子展示了bash shell所调用的ssh会话,前者运行在xterm中:
$ ps -u root f | grep -A2 xterm | head -315281 ? S 0:00 xterm15284 pts/20 Ss+ 0:00 \_ bash15286 pts/20 S+ 0:18 \_ ssh 192.168.1.2
[root@dev workspace]# ps -u root f | grep -A2 xterm | head -359 pts/0 S+ 0:00 \_ grep --color=auto -A2 xterm60 pts/0 S+ 0:00 \_ /usr/bin/coreutils --coreutils-prog-shebang=head /usr/bin/head -3
对 ps 输出进行排序
ps命令的输出默认是没有经过排序的。选项--sort可以强制ps对输出排序。参数前的+表示升序,-表示降序:
$ ps [OPTIONS] --sort -paramter1,+parameter2,parameter3..
例如,要列出占用CPU最多的前5个进程:
$ ps -eo comm,pcpu --sort -pcpu | head -5COMMAND %CPUinit 0.0init 0.0init 0.0bash 0.0
输出中显示了依据CPU占用率进行降序排列的前5个进程。
grep可以过滤ps的输出。要想找出当前运行的所有Bash进程,可以使用:
$ ps -eo comm,pid,pcpu,pmem | grep bashbash 9 0.0 0.0
根据真实用户/ID以及有效用户/ID过滤ps输出
ps命令可以根据指定的真实/有效用户名或ID(real and effective username or ID)对进程进行分组。通过检查每一条输出是否属于参数列表中指定的有效用户或真实用户,ps就能够过滤输出。
- 使用
-u EUSER1,EUSER2 …指定有效用户列表; - 使用
-U RUSER1,RUSER2 …指定真实用户列表。
例如:
# 显示以 root 作为有效用户 ID 和真实用户 ID 的用户以及 CPU 占用率$ ps -u root -U root -o user,pcpuUSER %CPUroot 0.0root 0.0root 0.0root 0.0root 0.0
-o可以和-e结合成-eo的形式,但如果使用了过滤器,就不能再使用-e了,它会使过滤器选项失效。
用 TTY过滤ps输出
可以通过指定进程所属的TTY来选择ps的输出。选项-t可以指定TTY列表:
$ ps -t TTY1, TTY2 ..
例如:
$ ps -tPID TTY STAT TIME COMMAND9 pts/0 Ss 0:00 -bash66 pts/0 R+ 0:00 ps -t
进程线程的相关信息
选项-L可以显示出线程的相关信息。该选项会在输出中添加一列LWP。如果再加上选项-f``(-LF),就会多显示出两列:NLWP(线程数量)和LWP(线程ID)
$ ps -LfUID PID PPID LWP C NLWP STIME TTY TIME CMDroot 9 8 9 0 1 19:24 pts/0 00:00:00 -bashroot 67 9 67 0 1 20:33 pts/0 00:00:00 ps -Lf
下面的命令可以列出线程数最多的5个进程:
$ ps -eLf --sort -nlwp | head -5UID PID PPID LWP C NLWP STIME TTY TIME CMDroot 1 0 1 0 3 19:24 ? 00:00:00 /initroot 1 0 5 0 3 19:24 ? 00:00:00 /initroot 1 0 6 0 3 19:24 ? 00:00:00 /initroot 7 1 7 0 1 19:24 ? 00:00:00 /init$ ps -eLf --sort -nlwp | headUID PID PPID LWP C NLWP STIME TTY TIME CMDroot 1 0 1 0 3 19:24 ? 00:00:00 /initroot 1 0 5 0 3 19:24 ? 00:00:00 /initroot 1 0 6 0 3 19:24 ? 00:00:00 /initroot 7 1 7 0 1 19:24 ? 00:00:00 /initroot 8 7 8 0 1 19:24 ? 00:00:00 /initroot 9 8 9 0 1 19:24 pts/0 00:00:00 -bashroot 70 9 70 0 1 20:34 pts/0 00:00:00 ps -eLf --sort -nlwproot 71 9 71 0 1 20:34 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=head /usr/bin/head
指定输出宽度以及所要显示的列
ps命令包含多种可用于选择输出字段的选项。下面表10-2是一些常用的选项。
表 10-2
-f |
显示完整格式,包括父进程的起始时间 |
|---|---|
-u userList |
选择userList中的用户所拥有的进程。默认情况下,ps只针对当前用户 |
-l |
长格式列表。显示用户ID、父进程PID、占用内存大小等内容 |
找出特定命令对应的进程 ID
假设某个命令有多个实例正在运行。在这种情况下,我们需要识别出这些进程的PID。ps和pgrep命令可以完成这项任务:
$ ps -C COMMAND_NAME
或者
$ ps -C COMMAND_NAME -o pid=
如果在pid后面加上=,这会去掉ps输出中PID一列的列名。要想移除某一列的列名,只需要把=
放在对应参数的后面就行了。
下面的命令可以列出bash进程的PID:
$ ps -C bash -o pid=9
pgrep命令也可以列出命令的进程ID列表:
$ pgrep bash
pgrep只需要使用命令名的一部分作为参数,例如pgrep ash或pgrep bas都没问题。但是ps需要你输入准确的命令名。pgrep也支持输出过滤选项。
如果不使用换行符作为分隔符,那么可以使用选项-d来指定其他的输出分隔符:
$ pgrep COMMAND -d DELIMITER_STRING$ pgrep bash -d ":"1255:1680
选项-u可以过滤用户:
$ pgrep -u root,slynux COMMAND
$ pgrep -u root,slynux bash9
其中,root和slynux都是用户名。
选项-c可以返回匹配的进程数量:
$ pgrep -c COMMAND$ pgrep -c bash1
确定系统繁忙程度
系统要么是处于空闲状态,要么是处于过载状态。load average的值描述了系统的负载情况。它指明了系统中可运行进程的平均数量。
uptime和top命令都可以显示平均负载。平均负载由3个值来指定,第1个值指明了1分钟内的平均值,第2个值指明了5分钟内的平均值,第3个值指明了15分钟内的平均值。
uptime命令的输出为:
$ uptime20:56:22 up 1:32, 0 users, load average: 0.00, 0.00, 0.00
top 命令
默认情况下,top命令会列出CPU占用最高的进程列表以及基本的系统统计信息,其中包括总的任务数、CPU核心数以及内存占用情况。命令输出每隔几秒钟就会更新一次。
下面的命令显示出了一些系统统计信息以及CPU占用率最高的进程:
$ toptop - 20:58:33 up 1:34, 0 users, load average: 0.00, 0.00, 0.00Tasks: 5 total, 1 running, 4 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 stMiB Mem : 7842.4 total, 7491.2 free, 235.8 used, 115.4 buff/cacheMiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 7419.9 avail MemPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND1 root 20 0 1756 1080 1016 S 0.0 0.0 0:00.00 init7 root 20 0 1756 80 0 S 0.0 0.0 0:00.00 init8 root 20 0 1756 80 0 S 0.0 0.0 0:00.21 init9 root 20 0 15108 3824 3152 S 0.0 0.0 0:00.27 bash95 root 20 0 52056 4124 3512 R 0.0 0.1 0:00.01 top
10.2.5 参考
10.8 节讲解了如何调度任务。
