14.4 进程与守护进程
14.4.1 进程与守护进程概述
FreeBSD 是一个多任务操作系统。任何时刻运行的程序均称为进程。每个运行的命令至少启动一个新进程,此外还有许多由 FreeBSD 运行的系统进程。
每个进程都由一个称为进程 ID(PID)的数字唯一标识。与文件类似,每个进程都有一个属主和组,属主和组权限用于确定进程可以打开哪些文件和设备。大多数进程还有一个启动它们的父进程。例如,shell 是一个进程,在 shell 中启动的任何命令都是以 shell 为父进程的进程。例外是特殊进程 init(8),其始终是系统启动时的首个进程,并且始终具有 PID 1。在 FreeBSD 中,所有进程都是以某个账户的名义启动的。
Port sysutils/htop 能够直观地呈现这一点(注意 △USER 这列):
$ htop
PID△USER PRI NI VIRT RES S CPU% MEM% TIME+ Command
1 root 20 0 12724 1324 S 0.0 0.0 0:00.08 /sbin/init
216 root 20 0 36172 7308 S 0.0 0.1 0:00.77 ├─ /usr/local/bin/vmtoolsd -c /usr/local/share/vmware-tools/to
400 root 48 0 14188 2684 S 0.0 0.0 0:00.00 ├─ dhclient: system.syslog
403 root 4 0 14188 2760 S 0.0 0.0 0:00.00 ├─ dhclient: em0 [priv]
481 _dhcp 20 0 14192 2808 S 0.0 0.0 0:00.01 ├─ dhclient: em0
596 root 20 0 15444 4204 S 0.0 0.1 0:00.05 ├─ /sbin/devd
800 root 20 0 13904 2792 S 0.0 0.0 0:00.02 ├─ /usr/sbin/syslogd -s
867 messagebus 20 0 15188 4492 S 0.0 0.1 0:00.29 ├─ /usr/local/bin/dbus-daemon --system
870 root 20 0 14120 2456 S 0.0 0.0 0:00.06 ├─ /usr/sbin/moused -p /dev/psm0 -t auto
898 ntpd 20 0 24564 5848 S 0.0 0.1 0:00.06 ├─ /usr/sbin/ntpd -p /var/db/ntp/ntpd.pid -c /etc/ntp.conf -f
944 root 68 0 23508 9560 S 0.0 0.1 0:00.00 ├─ sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups
947 root 20 0 13944 2576 S 0.0 0.0 0:00.02 ├─ /usr/sbin/cron -s
952 root 20 0 56736 23700 S 0.0 0.3 0:00.04 ├─ /usr/local/bin/sddm
980 root 20 0 257M 124M S 1.0 1.5 0:04.83 │ ├─ /usr/local/libexec/Xorg -nolisten tcp -background none -
993 root 23 0 50208 27572 S 0.0 0.3 0:00.02 │ └─ /usr/local/libexec/sddm-helper --socket /tmp/sddm-auth-4
994 ykla 68 0 19992 4620 S 0.0 0.1 0:00.01 │ └─ /usr/local/bin/ck-launch-session /usr/local/bin/start
1005 ykla 68 0 128M 67736 S 0.0 0.8 0:00.13 │ └─ /usr/local/bin/startplasma-x11
1010 ykla 68 0 128M 68184 S 0.0 0.8 0:00.25 │ └─ /usr/local/bin/plasma_session
1017 ykla 20 0 773M 190M S 0.0 2.3 0:01.33 │ ├─ /usr/local/bin/kded6
1018 ykla 20 0 676M 262M S 0.0 3.2 0:30.96 │ ├─ /usr/local/bin/kwin_x11有些程序并非为持续接收用户输入而设计,而是在启动后即与终端断开连接。例如,Web 服务器响应 Web 请求而非用户输入,邮件服务器是此类应用程序的另一个例子。这类程序被称为守护进程(daemon)。术语“daemon”来自希腊神话,代表一种非善非恶的实体,它默默执行有用的任务。因此,BSD 的吉祥物设计为身着运动鞋、手持草叉的快乐守护进程形象。在 Windows 系统中,这类程序被称为“服务”,可在任务管理器中查看。
这些长期在后台运行的服务通常命名为 xxxd,例如 sshd、ntpd,其中的 d 表示守护进程(daemon),这是 UNIX 系统的通用命名约定。例如,BIND 是 Berkeley Internet Name Domain,但实际执行的程序名为 named。Apache Web 服务器程序是 httpd,数据同步 Rsync 进程是 rsyncd。这仅是命名约定,例如数据库应用程序 MySQL 的守护进程是 mysql-server,而非 mysqld。
14.4.2 查看进程
用户只能向自己拥有的进程发送信号,root 用户可以向任何进程发送信号。SIGKILL 和 SIGSTOP 信号无法捕获或忽略。特殊 PID:0 发送到同组所有进程,-1 发送到所有进程(root)或自己的所有进程。
要查看系统上运行的进程,可以使用 ps(1) 或 top(1)。FreeBSD 的 ps 基于 4.4BSD,BSD 风格关键字允许省略 -,如 ps auxww。
要显示当前运行进程的静态列表(包括它们的 PID、内存使用量和启动命令),使用 ps(1)。要以交互方式显示所有运行进程并每隔几秒更新显示以查看系统运行状态,使用 top(1)。
默认情况下,ps(1) 仅显示由当前用户拥有、且具有控制终端的进程:
$ ps
PID TT STAT TIME COMMAND
1971 0 Is 0:00.03 -sh (sh)
2183 1 Ss 0:00.05 -sh (sh)
2186 1 R+ 0:00.00 psps(1) 的输出由多列构成:
- PID 列显示进程 ID。PID 从 1 开始分配,递增至 99999 后回绕至起始值。若某个 PID 已被占用,则不会再次分配。
- TT 列显示程序运行所在的 tty,STAT 显示程序的状态。
- TIME 是程序在 CPU 上运行的时间量,这通常不是程序启动以来的经过时间,因为大多数程序在需要花费 CPU 时间之前会花费大量时间等待事件触发。
- COMMAND 是用于启动程序的命令。
有许多不同的选项可用于更改显示的信息。最有用的选项集之一是 auxww,其中:
a显示所有用户的有控制终端的进程的信息。若系统设置security.bsd.see_other_uids=0,则非 root 用户使用此选项将无法查看其他用户的进程u显示进程属主的用户名和内存使用量x显示守护进程的信息
ps -auxww 示例:
$ ps -auxww
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
root 11 1592.5 0.0 0 256 - RNL 11:51 648:25.89 [idle]
root 0 0.0 0.1 0 4240 - DLs 11:51 0:05.08 [kernel]
……省略部分输出……
_dhcp 792 0.0 0.1 14656 3532 - ICs 11:51 0:00.04 dhclient: em0 (dhclient)
root 1211 0.0 0.1 14652 3156 - Is 11:51 0:00.00 /usr/sbin/moused -p /dev/input/event5 -t evdev -I /var/run/moused.event5.pid
……省略部分输出……
root 1974 0.0 0.1 14816 3532 0 I 12:04 0:00.01 su
root 1975 0.0 0.1 14872 3728 0 I+ 12:04 0:00.03 su (sh)
ykla 2183 0.0 0.1 14872 3728 1 Ss 12:28 0:00.05 -sh (sh)
ykla 2191 0.0 0.1 14956 3576 1 R+ 12:31 0:00.00 ps -auxww选项 ww 可以使 ps(1) 显示每个进程的完整命令行,而非在超出屏幕宽度时截断。但是,在某些情况下,使用带有 ww 选项的 ps 时,输出可能仍然被截断,因为内核中存储的命令行长度有限制。对于内核线程,命令字段可能显示为 [ ] 包裹的名称。
top(1) 的输出如下:
$ top
last pid: 2189; load averages: 0.24, 0.13, 0.04 up 0+00:39:10 12:30:35
30 processes: 1 running, 29 sleeping
CPU: 0.0% user, 0.0% nice, 0.0% system, 0.0% interrupt, 100% idle
Mem: 26M Active, 21M Inact, 260M Wired, 2056K Buf, 3617M Free
ARC: 35M Total, 6321K MFU, 27M MRU, 128K Anon, 407K Header, 1467K Other
19M Compressed, 52M Uncompressed, 2.76:1 Ratio
Swap: 8192M Total, 8192M Free
PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND
2183 ykla 1 0 0 15M 3728K wait 9 0:00 0.10% sh
1623 ntpd 2 0 0 26M 7072K select 12 0:00 0.00% ntpd
1783 root 1 0 0 15M 3708K ttyin 5 0:00 0.00% sh
2179 root 1 3 0 25M 12M select 12 0:00 0.00% sshd-session
1714 root 1 0 0 25M 11M select 5 0:00 0.00% sshd
1756 root 1 1 0 14M 3076K nanslp 14 0:00 0.00% cron
1496 root 1 0 0 14M 3456K kqread 15 0:00 0.00% syslogd
1224 root 1 0 0 16M 4668K select 0 0:00 0.00% devd
1967 root 1 1 0 25M 12M select 11 0:00 0.00% sshd-session
792 _dhcp 1 0 0 14M 3532K select 1 0:00 0.00% dhclient
2182 ykla 1 0 0 25M 12M select 4 0:00 0.00% sshd-session
1970 ykla 1 0 0 25M 12M select 5 0:00 0.00% sshd-session
1975 root 1 1 0 15M 3728K ttyin 1 0:00 0.00% sh
1971 ykla 1 9 0 15M 3720K wait 9 0:00 0.00% sh
1499 root 1 0 0 14M 3276K select 15 0:00 0.00% syslogd
1638 root 1 0 0 14M 3160K kqread 8 0:00 0.00% moused
1974 ykla 1 7 0 14M 3532K wait 15 0:00 0.00% su输出分为两个部分。头部(示例命令为前 7 行)显示最后运行的进程的 PID、系统负载平均值(衡量系统繁忙程度的指标)、系统正常运行时间(自上次重启以来的时间)和当前时间。头部中的其他数字与运行中的进程数量、已使用的内存和交换空间数量,以及系统在不同 CPU 状态下花费的时间有关。如果加载了 ZFS 文件系统模块,ARC 行指示从内存缓存而非磁盘读取了多少数据。
头部下方是一系列列,包含与 ps(1) 输出类似的信息,如 PID、用户名、CPU 时间量和启动进程的命令。在默认情况下,top(1) 还显示进程占用的内存空间量,分为两列:一列用于总大小,一列用于驻留大小。总大小是应用程序需要的内存量,驻留大小是它当前实际使用的量。top(1) 默认每两秒自动更新显示,可以使用 -s 指定不同的间隔,如 -s4 将每隔 4 秒刷新一次。
在非常繁忙的系统上,top 可能显示略微滞后的信息,因为采样需要时间。
14.4.3 终止进程
与任何运行中的进程或守护进程通信的一种方式是使用 kill(1) 发送信号。有许多不同的信号;有些具有特定含义,而其他信号在应用程序的文档中描述。用户只能向自己拥有的进程发送信号,向其他人的进程发送信号会提示权限不足。例外是 root 用户,其可向任何进程发送信号。
操作系统也可以向进程发送信号。如果应用程序编写不当并试图访问不应访问的内存,FreeBSD 将向进程发送“段违规”信号(SIGSEGV)。如果应用程序编写为使用 alarm(3) 系统调用在一段时间后收到警报,它将收到“闹钟”信号(SIGALRM)。
两个信号可用于停止进程:SIGTERM 和 SIGKILL。因为进程可以读取信号、关闭可能打开的任何日志文件,并尝试在关闭前完成正在执行的操作,SIGTERM 是终止进程的较为温和的方式。在某些情况下,如果进程正在执行某些无法中断的任务,它可能会忽略 SIGTERM。
进程无法忽略 SIGKILL。向进程发送 SIGKILL 通常会立即停止该进程。
其他常用的信号是 SIGHUP、SIGUSR1 和 SIGUSR2。由于这些是通用信号,不同的应用程序会有不同的响应。例如,在更改 Web 服务器的配置文件后,需要告诉 Web 服务器重新读取其配置。重启 httpd 会导致 Web 服务器短暂停机。相反,应向守护进程发送 SIGHUP 信号来使其重新读取配置。请注意,不同的守护进程会有不同的行为,因此请参阅守护进程的文档以确定 SIGHUP 是否能达到预期的结果。
随意终止系统中的进程是危险行为。尤其 init(8),PID 1 是最特殊的。
14.4.4 命令的前台与后台运行
Ctrl+Z:将当前进程挂起(暂停),随后可使用 fg 命令将其恢复到前台:
# ping 163.com # 测试与 163.com 的网络连通性
PING 163.com (59.111.160.244): 56 data bytes
64 bytes from 59.111.160.244: icmp_seq=0 ttl=52 time=27.611 ms
64 bytes from 59.111.160.244: icmp_seq=1 ttl=52 time=27.691 ms
^Z[1] + Suspended ping 163.com # 注意此处,按下了 Ctrl+Z
# fg # 返回前台
ping 163.com
64 bytes from 59.111.160.244: icmp_seq=3 ttl=52 time=27.465 ms
64 bytes from 59.111.160.244: icmp_seq=4 ttl=52 time=27.586 ms
64 bytes from 59.111.160.244: icmp_seq=5 ttl=52 time=27.522 ms
^C # 按 Ctrl+C 结束命令
--- 163.com ping statistics ---
6 packets transmitted, 6 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 27.465/27.596/27.701/0.085 ms14.4.5 附录:系统监控工具 htop
14.4.5.1 安装与配置
使用 pkg 二进制包管理器安装:
# pkg install htop或使用 Port 从源代码构建安装:
# cd /usr/ports/sysutils/htop/
# make install clean14.4.5.2 htop 配置持久化
可通过界面或配置文件持久化 htop 的配置。需注意:默认配置下,使用 F10 保存后无法通过 Ctrl + C 退出,必须选择 quit 选项才能确保配置保存;也可直接通过编辑配置文件设置。
编辑用户目录下的 ~/.config/htop/htoprc 配置文件,添加以下内容以启用 CPU 频率和温度显示功能:
show_cpu_frequency=1 # 启用 CPU 当前频率显示
show_cpu_temperature=1 # 启用 CPU 温度显示14.4.5.3 参考文献
- htop-dev. Settings are not saved[EB/OL]. [2026-03-25]. https://github.com/htop-dev/htop/issues/949. 讨论了 htop 配置保存的常见问题与解决方案。
14.4.6 课后习题
- 使用
ps aux和top查看系统运行的进程,按用户进程与系统守护进程进行分类,分析两类进程在父进程关系和会话组上的特征差异。 - 使用
nice和renice修改进程优先级,记录不同 nice 值对 CPU 密集型任务执行时间的影响,分析 FreeBSD 调度程序对优先级的处理机制。 - 编写一个简单的守护进程脚本,配置为 rc.d 服务,使用
service命令启动、停止和查询其状态,记录服务生命周期管理的完整流程。