3.8.进程和守护进程¶
FreeBSD 是一个多任务的操作系统。每个正在运行的程序都被称为 进程。每个正在运行的命令都至少会启动一个新的进程,并且有许多系统进程因 FreeBSD 而运行。
每个进程都由一个称为进程 ID(PID) 的唯一数字来识别。与文件类似,每个进程都有一个所有者和组,所有者和组的权限被用来决定进程可以打开哪些文件和设备。大多数进程也有一个启动它们的父进程。例如,shell 是一个进程,在 shell 中启动的任何命令都是一个以 shell 为父进程的进程。例外的是一个叫做 init(8) 的特殊进程,它是在启动时第一个启动的进程,它的 PID 总是为 1
。
有些程序的设计不是为了在用户连续输入的情况下运行,而是一有机会就断开与终端的连接。例如,网络服务器响应的是网络请求,而非用户输入。邮件服务器是这种类型的应用程序的另一个例子。这些类型的程序被称为 守护进程。守护进程这一术语来自希腊神话,代表了一个既非善也非恶的存在,却在无形中执行着有用的任务。这就是为什么 BSD 的吉祥物是一个穿着帆布鞋、拿着干草叉、看起来很欢快的小恶魔。
有一个惯例是那些作为守护进程运行的程序通常在尾部会加一个字母的“d”。例如,BIND 是 Berkeley Internet Name Domain,但实际执行的程序被命名为 named
。Apache 网络服务器程序是 httpd
,行式打印机的 spooling daemon 是 lpd
。这只是一个命名惯例,现实情况并不总是这样。例如,sendmail 应用程序的主要邮件守护进程是 sendmail
,而不是 maild
。
3.8.1.查看进程¶
要查看系统中运行的进程,使用 ps(1) 或 top(1)。要显示当前正在运行的进程的静态列表、它们的 PID、它们正在使用多少内存以及它们是用什么命令启动的,使用 ps(1)。要显示所有正在运行的进程并每隔几秒钟更新一次,以便交互式地查看计算机正在做什么,使用 top(1)。
默认情况下,ps(1) 只显示正在运行并由用户拥有的命令。比如:
% ps
输出结果应类似于下面的内容:
PID TT STAT TIME COMMAND
8203 0 Ss 0:00.59 /bin/csh
8895 0 R+ 0:00.00 ps
ps(1) 的输出被组织成若干列。PID
列显示进程的 ID。PID 从 1
开始分配,一直到 99999
,然后再绕回开头。然而,如果一个 PID 已经被使用,则不会被重新分配。TT
列显示了程序正在运行的 tty,STAT
显示了程序的状态。TIME
是该程序在 CPU 上运行的时间。这通常不是程序启动后所经过的时间,因为大多数程序在需要在 CPU 上花费时间之前,会花很多时间来等待事情的发生。最后,COMMAND
是用来启动程序的命令。
有许多不同的选项可以改变所显示的信息。其中最有用的一组是 auxww
,a
显示所有用户的所有运行进程的信息,u
显示进程所有者的用户名和内存使用情况,x
显示守护进程的信息,ww
强制使 ps(1) 显示每个进程的完整命令行,不因为它太长、无法在屏幕上显示而截断它。
top(1) 的输出也类似:
% top
输出结果应类似于下面的内容:
last pid: 9609; load averages: 0.56, 0.45, 0.36 up 0+00:20:03 10:21:46
107 processes: 2 running, 104 sleeping, 1 zombie
CPU: 6.2% user, 0.1% nice, 8.2% system, 0.4% interrupt, 85.1% idle
Mem: 541M Active, 450M Inact, 1333M Wired, 4064K Cache, 1498M Free
ARC: 992M Total, 377M MFU, 589M MRU, 250K Anon, 5280K Header, 21M Other
Swap: 2048M Total, 2048M Free
PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND
557 root 1 -21 r31 136M 42296K select 0 2:20 9.96% Xorg
8198 dru 2 52 0 449M 82736K select 3 0:08 5.96% kdeinit4
8311 dru 27 30 0 1150M 187M uwait 1 1:37 0.98% firefox
431 root 1 20 0 14268K 1728K select 0 0:06 0.98% moused
9551 dru 1 21 0 16600K 2660K CPU3 3 0:01 0.98% top
2357 dru 4 37 0 718M 141M select 0 0:21 0.00% kdeinit4
8705 dru 4 35 0 480M 98M select 2 0:20 0.00% kdeinit4
8076 dru 6 20 0 552M 113M uwait 0 0:12 0.00% soffice.bin
2623 root 1 30 10 12088K 1636K select 3 0:09 0.00% powerd
2338 dru 1 20 0 440M 84532K select 1 0:06 0.00% kwin
1427 dru 5 22 0 605M 86412K select 1 0:05 0.00% kdeinit4
输出被分成两部分。标题(前五或六行)显示了最后一个运行的进程的 PID,系统负载平均数(衡量系统有多忙),系统运行时间(自上次重启后的时间)和当前时间。标题中的其他数字涉及到有多少进程正在运行,有多少内存和交换空间被使用,以及系统在不同的 CPU 状态下花费了多少时间。如果已经加载 ZFS 文件系统模块,ARC
行表明有多少数据是从内存缓存中而不是从磁盘中读取的。
在标题下面是一系列列,包含与 ps(1) 输出的类似信息,例如 PID、用户名、CPU 时间和启动进程的命令。默认情况下,top(1) 还显示进程占用的内存空间。这被分成两列:一列是总大小,一列是常驻大小。总大小是指应用程序需要多少内存,常驻大小是指它现在实际使用多少内存。
top(1) 每两秒钟自动更新一次显示。可以用 -s
指定不同的间隔时间。
3.8.2.结束进程¶
与正在运行的进程或守护进程沟通的一种方式是使用 kill(1) 发送 信号。有许多不同的信号;一些信号有特定的含义,而其他信号则在应用程序的文档中介绍。用户只能向自己的进程发送信号,向别人的进程发送信号会导致权限拒绝的错误。但 root
用户是个例外,他可以向任何人的进程发送信号。
操作系统也可以向进程发送一个信号。如果一个应用程序写得不好,并试图访问它不应该访问的内存,FreeBSD 将向该进程发送 Segmentation Violation
信号(SIGSEGV
)。如果一个应用程序被写成使用 alarm(3) 系统调用,在一段时间后被提醒,它将被发送“Alarm”信号(SIGALRM
)。
有两个信号可以用来停止一个进程:SIGTERM
和 SIGKILL
。SIGTERM
是杀死一个进程的温和方式,因为该进程可以读取该信号,关闭它可能打开的任何日志文件,并试图在关闭前完成它正在做的事情。在某些情况下,如果一个进程正在进行一些不能被中断的任务,它可能会忽略 SIGTERM
。
SIGKILL
不能被进程所忽略。向一个进程发送 SIGKILL
通常会使该进程立即停止。[注 1]
其他常用的信号有 SIGHUP
、SIGUSR1
和 SIGUSR2
。由于这些是通用的信号,不同的应用程序会有不同的反应。
例如,在改变了一个 Web 服务器的配置文件后,需要告诉 Web 服务器重新读取其配置。重启 httpd
会导致网络服务器出现短暂的中断期。相反,向守护进程发送 SIGHUP
信号可以取代重启。请注意,不同的守护进程会有不同的行为,所以请参考守护进程的文档,以确定 SIGHUP
是否能达到预期效果。
注 1
有几个任务是不能被中断的。例如,如果该进程试图从网络中的另一台计算机上读取文件,而另一台计算机不可用,那么该进程就被称为不可中断的。最终该进程将超时(通常在两分钟后)。一旦发生超时,该进程将被杀死。