监测程序
一, 探查进程
当程序运行在系统上时, 我们称之为进程(process). 想要监测这些进程, 需要熟悉 ps 命令的用法. ps 命令好比工具中的瑞士军刀, 它能输出运行在系统上的所有程序的许多信息.
但是随着 ps 命令的稳健而来的还有复杂性 -- 有数不清的参数, 这或许让 ps 命令成了最难掌握的命令. 大多数系统管理员在掌握了能提供他们需要信息的一组参数后, 就一直坚持只使用这组参数.
默认情况下, ps 命令并不会提供那么多的信息:
- [email protected]:~$ ps
- PID TTY TIME CMD
- 2051 pts/18 00:00:00 bash
- 2162 pts/18 00:00:00 ps
- [email protected]:~$
默认情况下, ps 命令只会显示运行在当前控制台下的属于当前用户的进程, 在此例中, 我们只运行了 bash shell(shell 也只是运行在系统上的另一个程序而已)以及 ps 命令本身.
上例中的基本输出显示了程序的进程 ID(Process ID, PID), 它们运行在哪个终端 (TTY) 以及进程已用的 CPU 时间.
Linux 系统中使用的 GNU ps 命令支持 3 种不同类型的命令行参数:
Unix 风格的参数, 前面加单破折线;
BSD 风格的参数, 前面不加破折线;
GNU 风格的长参数, 前面加双破折线.
1,Unix 风格的参数
Unix 风格的参数是从贝尔实验室开发的 AT&T Unix 系统上原有的 ps 命令继承下来的, 这些参数如下表所示
参数 | m 描述 |
-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 | 显示进程中的线程 & nbsp; |
-V | 显示 ps 命令的版本号 |
上面给出的参数已经很多了, 不过还有很多. 使用 ps 命令的关键不在于记住所有可用的参数, 而在于记住最有用的那些参数. 大多数 Linux 系统管理员都有自己的一组参数, 他们会牢牢记住这些用来提取有用的进程信息的参数. 举个例子, 如果你想查看系统上运行的所有进程, 可用 - ef 参数组合(ps 命令允许你像这样把参数组合在一起).
- [email protected]:~$ ps -ef
- UID PID PPID C STIME TTY TIME CMD
- root 1 0 0 05:25 ? 00:00:02 /sbin/init auto noprompt
- root 2 0 0 05:25 ? 00:00:00 [kthreadd]
- root 4 2 0 05:25 ? 00:00:00 [kworker/0:0H]
- root 6 2 0 05:25 ? 00:00:00 [mm_percpu_wq]
- root 7 2 0 05:25 ? 00:00:00 [ksoftirqd/0]
- root 8 2 0 05:25 ? 00:00:00 [rcu_sched]
- root 9 2 0 05:25 ? 00:00:00 [rcu_bh]
- root 10 2 0 05:25 ? 00:00:00 [migration/0]
- root 11 2 0 05:25 ? 00:00:00 [watchdog/0]
- root 12 2 0 05:25 ? 00:00:00 [cpuhp/0]
截取一段, Linux 系统上运行着很多进程. 这个例子用了两个参数:-e 参数指定显示所有运行在系统上的进程;-f 参数则扩展了输出, 这些扩展的列包含了有用的信息.
UID: 启动这些进程的用户.
PID: 进程的进程 ID.
PPID: 父进程的进程号(如果该进程是由另一个进程启动的).
C: 进程生命周期中的 CPU 利用率.
STIME: 进程启动时的系统时间.
TTY: 进程启动时的终端设备.
TIME: 运行进程需要的累计 CPU 时间.
CMD: 启动的程序名称.
上例子中输出了合理数量的信息, 这也正是大多数系统管理员希望看到的. 如果想要获得更多的信息, 可采用 - l 参数, 他会产生一个长格式输出.
- [email protected]:~$ ps -l
- F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
- 0 S 1000 2051 2045 0 80 0 - 7373 wait pts/18 00:00:00 bash
- 0 R 1000 2249 2051 0 80 0 - 8996 - pts/18 00:00:00 ps
- [email protected]:~$
注意使用了 - l 参数之后多出的那些列.
F: 内核分配给进程的系统标记.
S: 进程的状态(O 代表正在运行; S 代表在休眠; R 代表可运行, 正等待运行; Z 代表僵化 -- 僵尸进程, 进程已结束但父进程已不存在; T 代表停止).
PRI: 进程的优先级(越大的数字代表越低的优先级).
NI: 谦让度值用来参与决定优先级.
ADDR: 进程的内存地址.
SZ: 假如进程被换出, 所需交换空间的大致大小.
WCHAN: 进程休眠的内核函数的地址.
2,BSD 风格的参数
了解了 Unix 风格的参数之后, 我们来一起看一下 BSD 风格的参数. 伯克利软件发行版 (Berkeley software distribution,BSD) 是加州大学伯克利分校开发的一个 Unix 版本. 它和 AT&TUnix 系统有许多细小的不同, 这也导致了多年的 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 类型的参数有很多重叠的地方. 使用其中某种类型参数得到的信息也同样可以使用另一种获得. 大多数情况下, 你只要选择自己所喜欢格式的参数类型就行了(比如你在使用 Linux 之前就已经习惯 BSD 环境了). 在使用 BSD 参数时, ps 命令会自动改变输出以模仿 BSD 格式. 下例是使用 l 参数的输出:
- [email protected]:~$ ps l
- F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
- 0 1000 2051 2045 20 0 29492 4936 wait Ss pts/18 0:00 bash
- 0 1000 2354 2051 20 0 35984 1496 - R+ pts/18 0:00 ps l
- [email protected]:~$
注意, 其中大部分的输出列跟使用 Unix 风格参数时的输出是一样的, 只有一小部分不同.
VSZ: 进程在内存中的大小, 以千字节 (KB) 为单位.
RSS: 进程在未换出时占用的物理内存.
STAT: 代表当前进程状态的双字符状态码.
许多系统管理员都喜欢 BSD 风格的 l 参数. 它能输出更详细的进程状态码(STAT 列). 双字符状态码能比 Unix 风格输出的单字符状态码更清楚地表示进程的当前状态.
第一个字符采用了和 Unix 风格 S 列相同的值, 表明进程是在休眠, 运行还是等待. 第二个参数进一步说明进程的状态.
<: 该进程运行在高优先级上.
N: 该进程运行在低优先级上.
L: 该进程有页面锁定在内存中.
s: 该进程是控制进程.
l: 该进程是多线程的.
+: 该进程运行在前台.
从前面的例子可以看出, bash 命令处于休眠状态, 但同时它也是一个控制进程(在我的会话中, 它是主要进程), 而 ps 命令则运行在系统的前台.
3,GNU 长参数
最后, GNU 开发人员在这个新改进过的 ps 命令中加入了另外一些参数. 其中一些 GNU 长参数复制了现有的 Unix 或 BSD 类型的参数, 而另一些则提供了新功能. 下表列出了现有的 GNU 长参数.
参数 | 描述 |
--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 字符绘出可爱的图表.
- [email protected]:~$ ps --forest
- PID TTY TIME CMD
- 2051 pts/18 00:00:00 bash
- 43622 pts/18 00:00:00 \_ ps
- [email protected]:~$
二, 实时监测进程
ps 命令虽然在收集运行在系统上的进程信息时非常有用, 但也有不足之处: 它只能显示某个特定时间点的信息. 如果想观察那些频繁换进换出的内存的进程趋势, 用 ps 命令就不方便了.
而 top 命令刚好适用这种情况. top 命令跟 ps 命令相似, 能够显示进程信息, 但它是实时显示的, 下图是 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 命令的输出上有很大的控制权. 用这个工具就能经常找出占用系统大部分资源的罪魁祸首. 当然了, 一旦找到, 下一步就是结束这些进程.
三, 结束进程
作为系统管理员, 很重要的一个技能就是知道何时以及如何结束一个进程. 有时进程挂起了, 只需要动动手让进程重新运行或结束就行了. 但有时, 有的进程会耗尽 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 用户.
- [email protected]:~$ kill 6447
- bash: kill: (6447) - Operation not permitted
- [email protected]:~$
TERM 信号告诉进程可能的话就停止运行. 不过, 如果有不服管教的进程, 那它通常会忽略这个请求. 如果要强制终止,-s 参数支持制定其他信号(用信号名或信号值).
从下例中看出, kill 命令不会有任何输出.
- [email protected]:~$ kill 2120
- [email protected]:~$
要检查 kill 命令是否有效, 可再运行 ps 或 top 命令, 看看问题进程是否已停止.
2,killall 命令
killall 命令非常强大, 它支持通过进程名而不是 PID 来结束进程. killall 命令也支持通配符, 这在系统因负载过大而变得很慢时很有用.
- [email protected]:~$ killall http*
- http*: no process found
- [email protected]:~$
嗯, 我这台机器没有启动任何 http 的进程, 不过这个命令大家是可以尝试使用的
警告 以 root 用户身份登录系统时, 使用 killall 命令要特别小心, 因为很容易就会误用通配符而结束了重要的系统进程. 这可能会破坏文件系统.
来源: http://www.bubuko.com/infodetail-3340599.html