3.8.进程和守护进程

FreeBSD 是一个多任务的操作系统。每个正在运行的程序都被称为 进程。每个正在运行的命令都至少会启动一个新的进程,并且有许多系统进程因 FreeBSD 而运行。

每个进程都由一个称为进程 ID(PID) 的唯一数字来识别。与文件类似,每个进程都有一个所有者和组,所有者和组的权限被用来决定进程可以打开哪些文件和设备。大多数进程也有一个启动它们的父进程。例如,shell 是一个进程,在 shell 中启动的任何命令都是一个以 shell 为父进程的进程。例外的是一个叫做 init(8)open in new window 的特殊进程,它是在启动时第一个启动的进程,它的 PID 总是为 1

有些程序的设计不是为了在用户连续输入的情况下运行,而是一有机会就断开与终端的连接。例如,网络服务器响应的是网络请求,而非用户输入。邮件服务器是这种类型的应用程序的另一个例子。这些类型的程序被称为 守护进程。守护进程这一术语来自希腊神话,代表了一个既非善也非恶的存在,却在无形中执行着有用的任务。这就是为什么 BSD 的吉祥物是一个穿着帆布鞋、拿着干草叉、看起来很欢快的看起来很欢快的小恶魔。

有一个惯例是那些作为守护进程运行的程序通常在尾部会加一个字母的“d”。例如,BIND 是 Berkeley Internet Name Domain,但实际执行的程序被命名为 named。Apache 网络服务器程序是 httpd,行式打印机的 spooling daemon 是 lpd。这只是一个命名惯例,现实情况并不总是这样。例如,sendmail 应用程序的主要邮件守护进程是 sendmail,而不是 maild

3.8.1.查看进程

要查看系统中运行的进程,使用 ps(1)open in new windowtop(1)open in new window。要显示当前正在运行的进程的静态列表、它们的 PID、它们正在使用多少内存以及它们是用什么命令启动的,使用 ps(1)open in new window。要显示所有正在运行的进程并每隔几秒钟更新一次,以便交互式地查看计算机正在做什么,使用 top(1)open in new window

默认情况下,ps(1)open in new window 只显示正在运行并由用户拥有的命令。比如:

% ps
 PID TT  STAT    TIME COMMAND
8203  0  Ss   0:00.59 /bin/csh
8895  0  R+   0:00.00 ps

ps(1)open in new window 的输出被组织成若干列。PID 列显示进程的 ID。PID 从 1 开始分配,一直到 99999,然后再绕回开头。然而,如果一个 PID 已经被使用,则不会被重新分配。TT 列显示了程序正在运行的 tty,STAT 显示了程序的状态。TIME 是该程序在 CPU 上运行的时间。这通常不是程序启动后所经过的时间,因为大多数程序在需要在 CPU 上花费时间之前,会花很多时间来等待事情的发生。最后,COMMAND 是用来启动程序的命令。

有许多不同的选项可以改变所显示的信息。其中最有用的一组是 auxwwa 显示所有用户的所有运行进程的信息,u 显示进程所有者的用户名和内存使用情况,x 显示守护进程的信息,ww 强制使 ps(1)open in new window 显示每个进程的完整命令行,不因为它太长、无法在屏幕上显示而截断它。

top(1)open in new window 的输出也类似:

% 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)open in new window 输出的类似信息,例如 PID、用户名、CPU 时间和启动进程的命令。默认情况下,top(1)open in new window 还显示进程占用的内存空间。这被分成两列:一列是总大小,一列是常驻大小。总大小是指应用程序需要多少内存,常驻大小是指它现在实际使用多少内存。

top(1)open in new window 每两秒钟自动更新一次显示。可以用 -s 指定不同的间隔时间。

3.8.2.结束进程

与正在运行的进程或守护进程沟通的一种方式是使用 kill(1)open in new window 发送 信号。有许多不同的信号;一些信号有特定的含义,而其他信号则在应用程序的文档中介绍。用户只能向自己的进程发送信号,向别人的进程发送信号会导致权限拒绝的错误。但 root 用户是个例外,他可以向任何人的进程发送信号。

操作系统也可以向进程发送一个信号。如果一个应用程序写得不好,并试图访问它不应该访问的内存,FreeBSD 将向该进程发送 Segmentation Violation 信号(SIGSEGV)。如果一个应用程序被写成使用 alarm(3)open in new window 系统调用,在一段时间后被提醒,它将被发送“Alarm”信号(SIGALRM)。

有两个信号可以用来停止一个进程:SIGTERMSIGKILLSIGTERM 是杀死一个进程的温和方式,因为该进程可以读取该信号,关闭它可能打开的任何日志文件,并试图在关闭前完成它正在做的事情。在某些情况下,如果一个进程正在进行一些不能被中断的任务,它可能会忽略 SIGTERM

SIGKILL 不能被进程所忽略。向一个进程发送 SIGKILL 通常会使该进程立即停止。[注 1]

其他常用的信号有 SIGHUPSIGUSR1SIGUSR2。由于这些是通用的信号,不同的应用程序会有不同的反应。

例如,在改变了一个 Web 服务器的配置文件后,需要告诉 Web 服务器重新读取其配置。重启 httpd 会导致网络服务器出现短暂的中断期。相反,向守护进程发送 SIGHUP 信号可以取代重启。请注意,不同的守护进程会有不同的行为,所以请参考守护进程的文档,以确定 SIGHUP 是否能达到预期效果。

向一个进程发送信号的过程

这个例子显示了如何向 inetd(8)open in new window 发送一个信号。inetd(8)open in new window 的配置文件是 /etc/inetd.confinetd(8)open in new window 在被发送 SIGHUP 时将重新读取这个配置文件。

1.使用 pgrep(1)open in new window 找到要发送信号的进程的 PID。在这个例子中,inetd(8)open in new window 的 PID 是 198。

% pgrep -l inetd
198  inetd

2.使用 kill(1)open in new window 来发送信号。由于 inetd(8)open in new window 是由 root 拥有的,所以先用 su(1)open in new window 成为 root

% su
Password:
# /bin/kill -s HUP 198

像大多数 UNIX® 命令一样,即使 kill(1)open in new window 执行成功,也不打印任何输出。如果向一个不属于该用户的进程发送信号,将显示 kill: PID: Operation not permitted。误填 PID 会将信号发送到错误的进程,这可能会产生负面的结果,或者将信号发送到一个当前没有使用的 PID,导致错误 kill: PID: No such process

注意

为什么使用 /bin/kill?:

许多 shell 将 kill 作为一个内置命令,意味着将直接用 shell 发送信号,而非直接运行 /bin/kill。请注意,不同的 shell 有不同的语法来指定要发送的信号的名称。与其尝试学习全部所需的语法,不如指定 /bin/kill 更简单。

发送其他信号时,用信号的名称代替 TERMKILL 即可。

重要

杀死系统中的随机进程是一个坏主意。特别是 init(8)open in new windowPID1,很特别。运行 /bin/kill -s KILL 1 是一个快速的、不推荐的关闭系统的方法。在按下回车键之前,一定要仔细检查 kill(1)open in new window 的参数。

注 1

有几个任务是不能被中断的。例如,如果该进程试图从网络中的另一台计算机上读取文件,而另一台计算机不可用,那么该进程就被称为不可中断的。最终该进程将超时(通常在两分钟后)。一旦发生超时,该进程将被杀死。

Loading...