Linux系统管理员面临的最复杂的任务之一就是跟踪运行在系统中的程序——尤其是现在,
图形化桌面集成了大量的应用来生成一个完整的桌面环境。系统中总是运行着大量的程序。
好在有一些命令行工具可以使你的生活轻松一些。本节将会介绍一些能帮你在Linux系统上
管理程序的基本工具及其用法。
4.1.1 探查进程
当程序运行在系统上时,我们称之为进程(process)。想监测这些进程,需要熟悉ps命令的
用法。ps命令好比工具中的瑞士军刀,它能输出运行在系统上的所有程序的许多信息。
遗憾的是,随着它的稳健而来的还有复杂性——有数不清的参数,这或许让ps命令成了最难
掌握的命令。大多数系统管理员在掌握了能提供他们需要信息的一组参数之后,就一直坚持只使
用这组参数。
默认情况下,ps命令并不会提供那么多的信息:
$ ps PID TTY TIME CMD
3081 pts/0 00:00:00 bash
3209 pts/0 00:00:00 ps
$
没什么特别的吧?默认情况下,ps命令只会显示运行在当前控制台下的属于当前用户的进
程。在此例中,我们只运行了bash shell(注意,shell也只是运行在系统上的另一个程序而已)以
及ps命令本身。
上例中的基本输出显示了程序的进程ID(Process ID,PID)、它们运行在哪个终端(TTY)
以及进程已用的CPU时间。
说明 ps命令叫人头疼的地方(也正是它如此复杂的原因)在于它曾经有两个版本。每个版本都
有自己的命令行参数集,这些参数控制着输出什么信息以及如何显示。最近,Linux开发
人员已经将这两种ps命令格式合并到了单个ps命令中(当然,也加入了他们自己的风格)。
Linux系统中使用的GNU ps命令支持3种不同类型的命令行参数:
- Unix风格的参数,前面加单破折线;
- BSD风格的参数,前面不加破折线;
- GNU风格的长参数,前面加双破折线。
下面将进一步解析这3种不同的参数类型,并举例演示它们如何工作。
1. Unix风格的参数
Unix风格的参数是从贝尔实验室开发的AT&T Unix系统上原有的ps命令继承下来的。这些参
数如表4-1所示。
① 关于session leader的概念,可参考《Unix环境高级编程(第3版)》第9章的内容。
② 这个在不同的Linux发行版中可能不尽相同,有的发行版中grplist代表会话ID,有的发行版中grplist代表有效组ID。
上面给出的参数已经很多了,不过还有很多。使用ps命令的关键不在于记住所有可用的参数,
而在于记住最有用的那些参数。大多数Linux系统管理员都有自己的一组参数,他们会牢牢记住
这些用来提取有用的进程信息的参数。举个例子,如果你想查看系统上运行的所有进程,可用-ef
参数组合(ps命令允许你像这样把参数组合在一起)。
① security context也叫security label,是SELinux采用的声明资源的一种机制。
上例中,我们略去了输出中的不少行,以节约空间。但如你所见,Linux系统上运行着很多
进程。这个例子用了两个参数:-e参数指定显示所有运行在系统上的进程;-f参数则扩展了输
出,这些扩展的列包含了有用的信息。
- UID:启动这些进程的用户。
- PID:进程的进程ID。
- PPID:父进程的进程号(如果该进程是由另一个进程启动的)。
- C:进程生命周期中的CPU利用率。
- STIME:进程启动时的系统时间。
- TTY:进程启动时的终端设备。
- TIME:运行进程需要的累计CPU时间。
- CMD:启动的程序名称。
上例中输出了合理数量的信息,这也正是大多数系统管理员希望看到的。如果想要获得更多
的信息,可采用-l参数,它会产生一个长格式输出。
注意使用了-l参数之后多出的那些列。
- F:内核分配给进程的系统标记。
- S:进程的状态(O代表正在运行;S代表在休眠;R代表可运行,正等待运行;Z代表僵化,进程已结束但父进程已不存在;T代表停止)。
- PRI:进程的优先级(越大的数字代表越低的优先级)。
- NI:谦让度值用来参与决定优先级。
- ADDR:进程的内存地址。
- SZ:假如进程被换出,所需交换空间的大致大小。
- WCHAN:进程休眠的内核函数的地址。
2. BSD风格的参数
了解了Unix风格的参数之后,我们来一起看一下BSD风格的参数。伯克利软件发行版
(Berkeley software distribution,BSD)是加州大学伯克利分校开发的一个Unix版本。它和AT&T
Unix系统有许多细小的不同,这也导致了多年的Unix争论。BSD版的ps命令参数如表4-2所示。
如你所见,Unix和BSD类型的参数有很多重叠的地方。使用其中某种类型参数得到的信息也
同样可以使用另一种获得。大多数情况下,你只要选择自己所喜欢格式的参数类型就行了(比如
你在使用Linux之前就已经习惯BSD环境了)。
在使用BSD参数时,ps命令会自动改变输出以模仿BSD格式。下例是使用l参数的输出:
注意,其中大部分的输出列跟使用Unix风格参数时的输出是一样的,只有一小部分不同。
- VSZ:进程在内存中的大小,以千字节(KB)为单位。
- RSS:进程在未换出时占用的物理内存。
- STAT:代表当前进程状态的双字符状态码。
许多系统管理员都喜欢BSD风格的l参数。它能输出更详细的进程状态码(STAT列)。双字
符状态码能比Unix风格输出的单字符状态码更清楚地表示进程的当前状态。
第一个字符采用了和Unix风格S列相同的值,表明进程是在休眠、运行还是等待。第二个参
数进一步说明进程的状态。
- <:该进程运行在高优先级上。
- N:该进程运行在低优先级上。
- L:该进程有页面锁定在内存中。
- s:该进程是控制进程。
- l:该进程是多线程的。
- +:该进程运行在前台。
从前面的例子可以看出,bash命令处于休眠状态,但同时它也是一个控制进程(在我的会
话中,它是主要进程),而ps命令则运行在系统的前台。
3. GNU长参数
最后,GNU开发人员在这个新改进过的ps命令中加入了另外一些参数。其中一些GNU长参数
复制了现有的Unix或BSD类型的参数,而另一些则提供了新功能。表4-3列出了现有的GNU长参数。
可以将GNU长参数和Unix或BSD风格的参数混用来定制输出。GNU长参数中一个着实让人
喜爱的功能就是—forest参数。它会显示进程的层级信息,并用ASCII字符绘出可爱的图表。
4.1.2 实时监测进程
ps命令虽然在收集运行在系统上的进程信息时非常有用,但也有不足之处:它只能显示
某个特定时间点的信息。如果想观察那些频繁换进换出的内存的进程趋势,用ps命令就不方
便了。
而top命令刚好适用这种情况。top命令跟ps命令相似,能够显示进程信息,但它是实时显
示的。图4-1是top命令运行时输出的截图。
输出的第一部分显示的是系统的概况:第一行显示了当前时间、系统的运行时间、登录的用
户数以及系统的平均负载。
平均负载有3个值:最近1分钟的、最近5分钟的和最近15分钟的平均负载。值越大说明系统
的负载越高。由于进程短期的突发性活动,出现最近1分钟的高负载值也很常见,但如果近15分
钟内的平均负载都很高,就说明系统可能有问题。
说明 Linux系统管理的要点在于定义究竟到什么程度才算是高负载。这个值取决于系统的硬件
配置以及系统上通常运行的程序。对某个系统来说是高负载的值可能对另一系统来说就
是正常值。通常,如果系统的负载值超过了2,就说明系统比较繁忙了。
第二行显示了进程概要信息——top命令的输出中将进程叫作任务(task):有多少进程处在
运行、休眠、停止或是僵化状态(僵化状态是指进程完成了,但父进程没有响应)。
下一行显示了CPU的概要信息。top根据进程的属主(用户还是系统)和进程的状态(运行、
空闲还是等待)将CPU利用率分成几类输出。
紧跟其后的两行说明了系统内存的状态。第一行说的是系统的物理内存:总共有多少内存,
当前用了多少,还有多少空闲。后一行说的是同样的信息,不过是针对系统交换空间(如果分配
了的话)的状态而言的。
最后一部分显示了当前运行中的进程的详细列表,有些列跟ps命令的输出类似。
- PID:进程的ID。
- USER:进程属主的名字。
- PR:进程的优先级。
- NI:进程的谦让度值。
- VIRT:进程占用的虚拟内存总量。
- RES:进程占用的物理内存总量。
- SHR:进程和其他进程共享的内存总量。
- S:进程的状态(D代表可中断的休眠状态,R代表在运行状态,S代表休眠状态,T代表
跟踪状态或停止状态,Z代表僵化状态)。
- %CPU:进程使用的CPU时间比例。
- %MEM:进程使用的内存占可用内存的比例。
- TIME+:自进程启动到目前为止的CPU时间总量。
- COMMAND:进程所对应的命令行名称,也就是启动的程序名。
默认情况下,top命令在启动时会按照%CPU值对进程排序。可以在top运行时使用多种交互
命令重新排序。每个交互式命令都是单字符,在top命令运行时键入可改变top的行为。键入f允
许你选择对输出进行排序的字段,键入d允许你修改轮询间隔。键入q可以退出top。用户在top
命令的输出上有很大的控制权。用这个工具就能经常找出占用系统大部分资源的罪魁祸首。当然
了,一旦找到,下一步就是结束这些进程。这也正是接下来的话题。
4.1.3 结束进程
作为系统管理员,很重要的一个技能就是知道何时以及如何结束一个进程。有时进程挂起了,
只需要动动手让进程重新运行或结束就行了。但有时,有的进程会耗尽CPU且不释放资源。在这
两种情景下,你就需要能控制进程的命令。Linux沿用了Unix进行进程间通信的方法。
在Linux中,进程之间通过信号来通信。进程的信号就是预定义好的一个消息,进程能识别
它并决定忽略还是作出反应。进程如何处理信号是由开发人员通过编程来决定的。大多数编写完
善的程序都能接收和处理标准Unix进程信号。这些信号都列在了表4-4中。
1. kill命令
kill命令可通过进程ID(PID)给进程发信号。默认情况下,kill命令会向命令行中列出的
全部PID发送一个TERM信号。遗憾的是,你只能用进程的PID而不能用命令名,所以kill命令有
时并不好用。
要发送进程信号,你必须是进程的属主或登录为root用户。
$ kill 3940
-bash: kill: (3940) - Operation not permitted
$
TERM信号告诉进程可能的话就停止运行。不过,如果有不服管教的进程,那它通常会忽略
这个请求。如果要强制终止,-s参数支持指定其他信号(用信号名或信号值)。
你能从下例中看出,kill命令不会有任何输出。
kill -s HUP 3940
要检查kill命令是否有效,可再运行ps或top命令,看看问题进程是否已停止。
2. killall命令
killall命令非常强大,它支持通过进程名而不是PID来结束进程。killall命令也支持通
配符,这在系统因负载过大而变得很慢时很有用。
killall http*
上例中的命令结束了所有以http开头的进程,比如Apache Web服务器的httpd服务。
警告 以root用户身份登录系统时,使用killall命令要特别小心,因为很容易就会误用通配符
而结束了重要的系统进程。这可能会破坏文件系统。