1 探查进程(ps 命令)
当程序运行在系统上时,我们称之为进程(process)。想监测这些进程,需要熟悉ps命令的用法。ps命令好比工具中的瑞士军刀,它能输出运行在系统上的所有程序的许多信息。
有数不清的参数,这或许让ps命令成了最难掌握的命令
默认情况下,ps命令并不会提供那么多的信息:
[admin@iZbp1hld5mqm15c6sdgqfkZ ~]$ ps
PID TTY TIME CMD
31281 pts/0 00:00:00 bash
31304 pts/0 00:00:00 ps
默认情况下,ps命令只会显示运行在当前控制台下的属于当前用户的进程。在此例中,我们只运行了bash shell(注意,shell也只是运行在系统上的另一个程序而已)以及ps命令本身。
基本输出显示了程序的进程ID(Process ID,PID)、它们运行在哪个终端(TTY)以及进程已用的CPU时间
Linux系统中使用的GNU ps命令支持3种不同类型的命令行参数:
- Unix风格的参数,前面加单破折线;
- BSD风格的参数,前面不加破折线;
- GNU风格的长参数,前面加双破折线
1.1 Unix风格的参数
Unix风格的参数是从贝尔实验室开发的AT&T Unix系统上原有的ps命令继承下来的,可选参数如下:
-A 显示所有进程
-N 显示与指定参数不符的所有进程
-a 显示除控制进程(session leader)和无终端进程外的所有进程
-d 显示除控制进程外的所有进程
-e 显示所有进程
-C cmdlist 显示包含在cmdlist列表中的进程
-G grplist 显示组ID在grplist列表中的进程
-U userlist 显示属主的用户ID在userlist列表中的进程
-g grplist 显示会话或组ID在grplist列表中的进程
-p pidlist 显示PID在pidlist列表中的进程
-s sesslist 显示会话ID在sesslist列表中的进程
-t ttylist 显示终端ID在ttylist列表中的进程
-u userlist 显示有效用户ID在userlist列表中的进程
-F 显示更多额外输出(相对-f参数而言)
-O format 显示默认的输出列以及format列表指定的特定列
-M 显示进程的安全信息
-c 显示进程的额外调度器信息
-f 显示完整格式的输出
-j 显示任务信息
-l 显示长列表
-o format 仅显示由format指定的列
-y 不要显示进程标记(process flag,表明进程状态的标记)
-Z 显示安全标签(security context)①信息
-H 用层级格式来显示进程(树状,用来显示父进程)
-n namelist 定义了WCHAN列显示的值
-w 采用宽输出模式,不限宽度显示
-L 显示进程中的线程
-V 显示ps命令的版本号
eg:如果你想查看系统上运行的所有进程,可用-ef参数组合
ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Feb25 ? 00:05:40 /usr/lib/systemd/systemd --swit
root 2 0 0 Feb25 ? 00:00:00 [kthreadd]
root 3 2 0 Feb25 ? 00:00:55 [ksoftirqd/0]
root 5 2 0 Feb25 ? 00:00:00 [kworker/0:0H]
root 7 2 0 Feb25 ? 00:00:00 [migration/0]
root 8 2 0 Feb25 ? 00:00:00 [rcu_bh]
root 9 2 0 Feb25 ? 00:03:57 [rcu_sched]
root 10 2 0 Feb25 ? 00:00:00 [lru-add-drain]
root 11 2 0 Feb25 ? 00:00:12 [watchdog/0]
root 13 2 0 Feb25 ? 00:00:00 [kdevtmpfs]
root 14 2 0 Feb25 ? 00:00:00 [netns]
主要包含了一下信息。
- UID:启动这些进程的用户。
- PID:进程的进程ID。
- PPID:父进程的进程号(如果该进程是由另一个进程启动的)。
- C:进程生命周期中的CPU利用率。
- STIME:进程启动时的系统时间。
- TTY:进程启动时的终端设备。
- TIME:运行进程需要的累计CPU时间。
- CMD:启动的程序名称。
如果想要获得更多的信息,可采用-l参数:
[admin@iZbp1hld5mqm15c6sdgqfkZ ~]$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 R 1000 1030 31281 0 80 0 - 38301 - pts/0 00:00:00 ps
0 S 1000 31281 31280 0 80 0 - 28859 do_wai pts/0 00:00:00 bash
使用了-l参数之后多出的那些列。
- F:内核分配给进程的系统标记。
- S:进程的状态(O代表正在运行;S代表在休眠;R代表可运行,正等待运行;Z代表僵化,进程已结束但父进程已不存在;T代表停止)。
- PRI:进程的优先级(越大的数字代表越低的优先级)。
- NI:谦让度值用来参与决定优先级。
- ADDR:进程的内存地址。
- SZ:假如进程被换出,所需交换空间的大致大小。
- WCHAN:进程休眠的内核函数的地址。
1.2 BSD风格的参数
伯克利软件发行版(Berkeley software distribution,BSD)是加州大学伯克利分校开发的一个Unix版本。它和AT&T Unix系统有许多细小的不同,这也导致了多年的Unix争论。
BSD版的ps命令参数如下所示:
T 显示跟当前终端关联的所有进程
a 显示跟任意终端关联的所有进程
g 显示所有的进程,包括控制进程
r 仅显示运行中的进程
x 显示所有的进程,甚至包括未分配任何终端的进程
U userlist 显示归userlist列表中某用户ID所有的进程
p pidlist 显示PID在pidlist列表中的进程
t ttylist 显示所关联的终端在ttylist列表中的进程
O format 除了默认输出的列之外,还输出由format指定的列
X 按过去的Linux i386寄存器格式显示
Z 将安全信息添加到输出中
j 显示任务信息
l 采用长模式
o format 仅显示由format指定的列
s 采用信号格式显示
u 采用基于用户的格式显示
v 采用虚拟内存格式显示
N namelist 定义在WCHAN列中使用的值
O order 定义显示信息列的顺序
S 将数值信息从子进程加到父进程上,比如CPU和内存的使用情况
c 显示真实的命令名称(用以启动进程的程序名称)
e 显示命令使用的环境变量
f 用分层格式来显示进程,表明哪些进程启动了哪些进程
h 不显示头信息
k sort 指定用以将输出排序的列
n 和WCHAN信息一起显示出来,用数值来表示用户ID和组ID
w 为较宽屏幕显示宽输出
H 将线程按进程来显示
m 在进程后显示线程
L 列出所有格式指定符
V 显示ps命令的版本号
Unix和BSD类型的参数有很多重叠的地方。使用其中某种类型参数得到的信息也同样可以使用另一种获得。大多数情况下,你只要选择自己所喜欢格式的参数类型就行了
$ ps l
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 500 3081 3080 20 0 4692 1432 wait Ss pts/0 0:00 -bash
0 500 5104 3081 20 0 4468 844 - R+ pts/0 0:00 ps l
- VSZ:进程在内存中的大小,以千字节(KB)为单位。
- RSS:进程在未换出时占用的物理内存。
- STAT:代表当前进程状态的双字符状态码。
许多系统管理员都喜欢BSD风格的l参数。它能输出更详细的进程状态码(STAT列)。双字符状态码能比Unix风格输出的单字符状态码更清楚地表示进程的当前状态。
第一个字符采用了和Unix风格S列相同的值,表明进程是在休眠、运行还是等待。第二个参数进一步说明进程的状态:
- <:该进程运行在高优先级上。
- N:该进程运行在低优先级上。
- L:该进程有页面锁定在内存中。
- s:该进程是控制进程。
- l:该进程是多线程的。
- +:该进程运行在前台
从前面的例子可以看出,bash命令处于休眠状态,但同时它也是一个控制进程(在我的会
话中,它是主要进程),而ps命令则运行在系统的前台。
1.3 GNU长参数
GNU开发人员在这个新改进过的ps命令中加入了另外一些参数。其中一些GNU长参数复制了现有的Unix或BSD类型的参数,而另一些则提供了新功能
--deselect 显示所有进程,命令行中列出的进程
--Group grplist 显示组ID在grplist列表中的进程
--User userlist 显示用户ID在userlist列表中的进程
--group grplist 显示有效组ID在grplist列表中的进程
--pid pidlist 显示PID在pidlist列表中的进程
--ppid pidlist 显示父PID在pidlist列表中的进程
--sid sidlist 显示会话ID在sidlist列表中的进程
--tty ttylist 显示终端设备号在ttylist列表中的进程
--user userlist 显示有效用户ID在userlist列表中的进程
--format format 仅显示由format指定的列
--context 显示额外的安全信息
--cols n 将屏幕宽度设置为n列
--columns n 将屏幕宽度设置为n列
--cumulative 包含已停止的子进程的信息
--forest 用层级结构显示出进程和父进程之间的关系
--headers 在每页输出中都显示列的头
--no-headers 不显示列的头
--lines n 将屏幕高度设为n行
--rows n 将屏幕高度设为n排
--sort order 指定将输出按哪列排序
--width n 将屏幕宽度设为n列
--help 显示帮助信息
--info 显示调试信息
--version 显示ps命令的版本号
可以将GNU长参数和Unix或BSD风格的参数混用来定制输出。GNU长参数中一个着实让人喜爱的功能就是–forest参数。它会显示进程的层级信息,并用ASCII字符绘出可爱的图表。
1981 ? 00:00:00 sshd
3078 ? 00:00:00 \_ sshd
3080 ? 00:00:00 \_ sshd
3081 pts/0 00:00:00 \_ bash
16676 pts/0 00:00:00 \_ ps
2 实时监测进程(top )
ps命令虽然在收集运行在系统上的进程信息时非常有用,但也有不足之处:它只能显示某个特定时间点的信息。如果想观察那些频繁换进换出的内存的进程趋势呢?
top命令跟ps命令相似,能够显示进程信息,但它是实时显示的。
输出的第一行显示的是系统的概况:第一行显示了当前时间、系统的运行时间、登录的用户数以及系统的平均负载。
top - 08:13:23 up 34 days, 11:29, 1 user, load average: 0.01, 0.02, 0.05
平均负载有3个值:最近1分钟的、最近5分钟的和最近15分钟的平均负载。值越大说明系统的负载越高。由于进程短期的突发性活动,出现最近1分钟的高负载值也很常见,但如果近15分钟内的平均负载都很高,就说明系统可能有问题。
Linux系统管理的要点在于定义究竟到什么程度才算是高负载。这个值取决于系统的硬件配置以及系统上通常运行的程序。对某个系统来说是高负载的值可能对另一系统来说就是正常值。通常,如果系统的负载值超过了2,就说明系统比较繁忙了。
第二行显示了进程概要信息——top命令的输出中将进程叫作任务(task):有多少进程处在运行、休眠、停止或是僵化状态(僵化状态是指进程完成了,但父进程没有响应)。
Tasks: 70 total, 1 running, 69 sleeping, 0 stopped, 0 zombie
第三行显示了CPU的概要信息。top根据进程的属主(用户还是系统)和进程的状态(运行、空闲还是等待)将CPU利用率分成几类输出。
%Cpu(s): 0.3 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
紧跟其后的两行说明了系统内存的状态。第一行说的是系统的物理内存:总共有多少内存,当前用了多少,还有多少空闲。后一行说的是同样的信息,不过是针对系统交换空间(如果分配了的话)的状态而言的。
KiB Mem : 1882232 total, 1067080 free, 109956 used, 705196 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1572440 avail Mem
最后一部分显示了当前运行中的进程的详细列表,有些列跟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。
3 结束进程
在Linux中,进程之间通过信号来通信。进程的信号就是预定义好的一个消息,进程能识别它并决定忽略还是作出反应。进程如何处理信号是由开发人员通过编程来决定的。大多数编写完善的程序都能接收和处理标准Unix进程信号。这些信号都列在了下表中:
信号 名称 描述
1 HUP 挂起
2 INT 中断
3 QUIT 结束运行
9 KILL 无条件终止
11 SEGV 段错误
15 TERM 尽可能终止
17 STOP 无条件停止运行,但不终止
18 TSTP 停止或暂停,但继续在后台运行
19 CONT 在STOP或TSTP之后恢复执行
在Linux上有两个命令可以向运行中的进程发出进程信号:
- kill命令
- killall命令
3.1 kill命令
kill命令可通过进程ID(PID)给进程发信号。默认情况下,kill命令会向命令行中列出的全部PID发送一个TERM信号。遗憾的是,你只能用进程的PID而不能用命令名,所以kill命令有时并不好用。
要发送进程信号,你必须是进程的属主或登录为root用户。
eg:
kill 3940
TERM信号告诉进程可能的话就停止运行。不过,如果有不服管教的进程,那它通常会忽略这个请求。如果要强制终止,-s参数支持指定其他信号(用信号名或信号值)。
kill -s HUP 3940
kill命令不会有任何输出,要检查kill命令是否有效,可再运行ps或top命令,看看问题进程是否已停止。
3.2 killall命令
killall命令非常强大,它支持通过进程名而不是PID来结束进程。killall命令也支持通配符,这在系统因负载过大而变得很慢时很有用。
killall http*
上例中的命令结束了所有以http开头的进程,比如Apache Web服务器的httpd服务。
以root用户身份登录系统时,使用killall命令要特别小心,因为很容易就会误用通配符而结束了重要的系统进程。这可能会破坏文件系统。