Shell 中监测程序进程

Shell 中监测程序进程

掌握基本 ps 命令

当程序在系统上运行时,会开启一个进程(process, an instance of a computer program that is being executed)。可以通过 ps 命令输出进程的许多信息,但是 ps 有数不清的可选参数,让 ps 成为最难掌握的命令之一。当然,熟悉并掌握一组常用参数满足需要就可以了。

查看进程

默认情况下,ps 命令只会显示运行在当前控制台下的属于当前用户的进程。如下图,这里只运行了 zsh 一个程序而已。

ps 命令输出

ps 基本输出显示了程序的进程 ID (Process ID, PID)、它们运行在哪个终端(TTY)以及进程已用的 CPU 时间。

ps 命令支持 3 种不同风格的命令行参数:

  • Unix 风格,前面加单破折号
  • BSD 风格,前面不加破折号
  • GNU 风格,前面加双破折号

Unix 风格的参数

Unix 风格的参数是从贝尔实验室开发的 AT&T Unix 系统上原有的 ps 命令继承下来的。如下表:

参数 描述
-A 显示所有进程
-N 显示与指定参数不符的所有进程
-a 显示除控制进程(session leader)和无终端进程外的所有进程
-d 显示除控制进程外的所有进程
-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 显示更多额外输出(相对 -f 参数而言)
-O format 显示默认的输出列以及 format 列表指定的特定列
-o format 仅显示由 format 指定的列
-M 显示进程的安全信息
-c 显示进程的额外调度器信息
-j 显示任务信息
-L 显示进程中的线程
-l 显示长列表
-y 不要显示进程标记
-Z 显示安全标签(security context)信息
-H 用层级格式来显示进程(树状,用来显示父进程)
-n namelist 定义了 WCHAN 列显示的值
-w 采用宽输出模式,不限宽度显示
-V 显示 ps 命令的版本号

当然,也可以使用组合参数,例如查看系统上运行的所有进程,可用 -ef 组合。一些常用的扩展信息如:

  • UID:启动这些进程的用户
  • PID:进程的进程 ID
  • PPID:父进程的进程号
  • C:进程生命周期中的 CPU 利用率
  • STIME:进程启动时的系统时间
  • TTY:进程启动时的终端设备
  • TIME:运行进程所需的累积 CPU 时间
  • CMD:启动的程序名称
  • F:内核分配给进程的系统标记
  • S:进程的状态(O 代表正在运行;S 代表休眠;R 代表可运行,正等待运行;Z 代表僵化,进程已结束但父进程已不存在;T 代表停止)
  • PRI:进程的优先级(越大的数字代表越低的优先级)
  • NI:谦让度值用来参与决定优先级
  • ADDR:进程的内存地址
  • SZ:假如进程被换出,所需交换空间的大致大小
  • WCHAN:进程休眠的内核函数的地址

BSD 风格的参数

伯克利软件发行版 (Berkeley software distribution,BSD) 是加州大学伯克利分校开发的一个 Unix 版本。它和 AT&T Unix 系统有许多细小的不同,这也导致了多年的 Unix 争论。

参数 描述
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 类型的参数有很多重叠的地方。使用其中某种类型参数得到的信息也同样可以使用另一种获得。大多数情况下,你只要选择自己所喜欢格式的参数类型就行了。

BSD 风格

许多系统管理员都喜欢 BSD 风格的 l 参数。它能输出更详细的进程状态码(STAT 列)、进程在内存中的大小(VSZ 列)及进程在未换出时占用的物理内存(RSS 列)。双字符状态码能比 Unix 风格输出的单字符状态码更清楚地表示进程的当前状态。

GNU 长参数

GNU 开发人员在 ps 命令中加入了另外一些参数。其中一些 GNU 长参数复制了现有的 Unix 或 BSD 类型的参数,而另一些则提供了新功能。在 OSX 上体会不到我就不展开了。

实时监测进程

ps 命令只能显示某个特定时间点的信息。如果想观察那些频繁换进换出的内存的进程趋势,用 ps 命令就不方便了。

top 命令刚好适用这种情况。top 命令跟 ps 命令相似,能够显示进程信息,但它是实时动态显示的。下图便是 top 命令运行时的输出截图。

top 命令运行截图

输出的第一部分显示的是系统的概况:第一行显示了当前时间、系统的运行时间、登录的用户数以及系统的平均负载。

第二行显示了进程概要信息—— top 命令的输出中将进程叫作任务 (task):有多少进程处在运行、休眠、停止或是僵化状态(僵化状态是指进程完成了,但父进程没有响应)。下一行显示了 CPU 的概要信息。top 根据进程的属主(用户还是系统)和进程的状态(运行、 空闲还是等待)将 CPU 利用率分成几类输出。

最后一部分显示了当前运行中的进程的详细列表,有些列跟 ps 命令的输出类似。

  • PID:进程的 ID
  • USER:进程属主的名字
  • PR:进程的优先级
  • NI:进程的谦让度值
  • VIRT:进程占用的虚拟内存总量
  • RES:进程占用的物理内存总量
  • SHR:进程和其他进程共享的内存总量
  • S:进程的状态
  • %CPU:进程使用的 CPU 时间比例
  • %MEM:进程使用的内存占可用内存的比例
  • TIME+:自进程启动到目前为止的 CPU 时间总量
  • COMMAND:进程所对应的命令行名称,也就是启动的程序名

默认情况下,top 命令在启动时会按照 %CPU 值对进程排序。

我们可以在 top 运行时使用多种交互命令重新排序。每个交互式命令都是单字符,在 top 命令运行时键入可改变 top 运行的行为。键入 f 允许你选择对输出进行排序的字段,键入 d 允许你修改轮询间隔。键入 q 就可以退出 top

结束进程

有时进程挂起了,需要手动让进程重新运行或结束。但有时,有的进程会耗尽 CPU 且不释放资源。在这两种情景下,你就需要能控制进程的命令。Linux 沿用了 Unix 进行进程间通信的方法。

在 Linux 中,进程之间通过信号来通信。进程的信号就是预定义好的一个消息,进程能识别它并决定忽略还是作出反应。进程如何处理信号是由开发人员通过编程来决定的。大多数编写完善的程序都能接收和处理标准 Unix 进程信号。

信号 名称 描述
1 HUP 挂起
2 INT 中断
3 QUIT 结束运行
9 KILL 无条件终止
11 SEGV 段错误
15 TERM 尽可能终止
17 STOP 无条件停止运行,但不终止
18 TSTP 停止或暂停,但继续在后台运行
19 CONT 在 STOP 或 TSTP 之后恢复执行

在 Linux 上有两个命令可以向运行中的进程发出进程信号。

  1. kill 命令

    kill 命令可通过进程 ID (PID) 给进程发信号。默认情况下,kill 命令会向命令行中列出的全部 PID 发送一个 TERM 信号。遗憾的是,你只能用进程的 PID 而不能用命令名,所以 kill 命令有时并不好用。要发送进程信号,你必须是进程的属主或登录为 root 用户。

    TERM 信号告诉进程可能的话就停止运行。不过,如果有不服管教的进程,那它通常会忽略这个请求。如果要强制终止,-s 参数支持指定其他信号(用信号名或信号值)。

     # kill -s HUP 3940
     #
    

    kill 命令不会有任何输出,要检查 kill 命令是否有效,可再运行 pstop 命令,看看问题进程是否已停止。

  2. killall 命令

    killall 命令非常强大,它支持通过进程名而不是 PID 来结束进程。killall 命令也支持通配符,这在系统因负载过大而变得很慢时很有用。

     # killall http*
     #
    

    上例中的命令结束了所有以 http 开头的进程,比如 Apache Web 服务器的 httpd 服务。

    以 root 用户身份登录系统时,使用 killall 命令要特别小心,因为很容易就会误用通配符而结束了重要的系统进程。这可能会破坏文件系统。

好了,慢慢摸索这些命令,偷偷看看系统在干些什么吧……

林宏

Frank Lin

Hey, there! This is Frank Lin (@flinhong), one of the 1.4 billion 🇨🇳. This 'inDev. Journal' site holds the exploration of my quirky thoughts and random adventures through life. Hope you enjoy reading and perusing my posts.

YOU MAY ALSO LIKE

Shell 简介

Linux Notes

2017.09.03

Shell 简介

在 Linux 系统上,通常有好几种 Linux shell 可用。不同的 shell 有不同的特性,有些更利于创建脚本,有些则更利于管理进程。Shell 虽然不是 Unix/Linux 系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式来协调各个程序的运行。