进程的组成部分
PID: 进程的 ID 号
PID - Process ID
内核给每个进程分配一个独一无二的 ID 号,控制进程的大多数命令和系统调用需要用户指定 PID 来标识操作的目标。PID 按照创建进程的顺序来分配。
PPID: 父 PID 号
PPID - Parent Process ID
当一个进程被克隆时,原来的进程就叫做父进程,而克隆出的副本则叫做子进程。进程的 PPID 属性就是克隆它的父进程的 PID。至少最初是这样。如果原来的父进程终止,那么init(进程 1)就成为新的父进程。
UID 和 EUID: 真实的和有效的用户 ID
UID - User ID
EUID - Effective User ID
进程的 UID 就是进程创建者的用户标识号,或者更确切地说,就是复制了父进程的的 UID 值。
EUID 是“有效(effective)”的用户 ID,这是一个额外的 UID,对于大多数进程而言,UID 和 EUID 是一样的,例外的情况是 setuid 程序。
Linux 还有一种“Saved User ID”,它是进程刚开始执行时刻,进程 EUID 的副本。除非进程采取措施删除这个保存下来的 UID,否则它就留了下来,作为真实的或者有效的 UID 来用。
Linux 还定义了一种非标准的进程参数 FSUID,它控制着对文件系统权限的判断,但在内核之外并不常用。
GID 和 EGID: 真实的和有效的组 ID
GID - Group ID
EGID - Effective Group ID
GID 就是进程的组 ID。EGID 与 GID 的关系跟 EUID 与 UID 的关系相同,因为它可以由一个 setgid 程序来“转换”。Linux 有一种 SGID(Saved GID),就像有 Saved UID 一样。
信号(Signal)
信号是进程级的中断请求。《Linux Administration Handbook》一书上讲到“系统定义了大约 30 种不同种类的信号”,而现代 Linux 系统则定义了 64 种不同种类的信号。执行bash 的内置命令
可以获得一份信号名称和编号的清单。(Ubuntu 10.10, Fedora 17)
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
下表列出了所有系统管理员都应该清楚的信号。
# | 名称 | 描述 |
---|---|---|
1 | SIGHUP | 挂起 |
2 | SIGINT | 中断 |
3 | SIGQUIT | 退出 |
9 | SIGKILL | 杀死 |
7 | SIGBUS | 总线错误 |
11 | SIGSEGV | 段错误 |
15 | SIGTERM | 软件终止 |
19 | SIGSTOP | 停止 |
20 | SIGTSTP | 键盘停止 |
18 | SIGCONT | 停止以后继续 |
28 | SIGWINCH | 窗口改变 |
10 | SIGUSR1 | 用户定义 |
12 | SIGUSR2 | 用户定义 |
kill 和 killall: 发送信号
顾名思义,kill 命令最直接的用法是终止一个进程。kill 能够发送任何信号,但在默认情况下,它发送一个 SIGTERM 信号。kill 可以被普通用户用在他们自己的进程上,或者被超级用户用在任何进程上。语法是:
这里的 signal 就是要发送信号的编号或符号名称(如上表所示),pid 就是目标进程的 ID。pid 为 -1 会把这个信号广播给除了init 以外的所有进程。
没有信号编号的 kill 命令不保证进程会被杀死,因为 SIGTERM 信号可能被捕获、封锁或忽略。下面的命令:
将“保证”进程的消亡,因为信号 9,即 SIGKILL 不能够被捕获到。我们给“保证”加引号是因为进程的生命力有时候能够变得相当“旺盛”,以致于连 SIGKILL 也不能够影响到它们(通常是由于有些退化的 I/O 虚假锁定,例如等待已经停止旋转的磁盘)。重新启动系统通常是解决这些“不听话”的进程的惟一方法。
如果用户不知道要发信号的进程的 PID,一般应该用 ps 命令查出来,另一种方法是使用 killall 命令,该命令替用户查出进程的 PID。例如:
注意,如果用户的输入匹配多个进程,那么就会把 killall 信号发给所有匹配的进程。
普通的 kill 命令实际上有类似的功能,但是在匹配命令名上似乎没有 killall 那么聪明。所以还是坚持使用killall 吧。
ps: 监视进程
ps 是系统管理员监视进程的主要工具。用户可以用命令 ps aux 了解正在系统上运行的所有进程的全貌。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 2880 1712 ? Ss 19:23 0:00 /sbin/init root 2 0.0 0.0 0 0 ? S 19:23 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? S 19:23 0:00 [ksoftirqd/0] root 4 0.0 0.0 0 0 ? S 19:23 0:00 [migration/0] root 5 0.0 0.0 0 0 ? S 19:23 0:00 [watchdog/0] root 6 0.0 0.0 0 0 ? S 19:23 0:00 [migration/1] root 7 0.0 0.0 0 0 ? S 19:23 0:00 [ksoftirqd/1] root 8 0.0 0.0 0 0 ? S 19:23 0:00 [watchdog/1] root 9 0.0 0.0 0 0 ? S 19:23 0:00 [migration/2] root 10 0.0 0.0 0 0 ? S 19:23 0:00 [ksoftirqd/2] root 11 0.0 0.0 0 0 ? S 19:23 0:00 [watchdog/2] root 12 0.0 0.0 0 0 ? S 19:23 0:00 [migration/3] root 13 0.0 0.0 0 0 ? S 19:23 0:00 [ksoftirqd/3]
中括号括起来的命令名不是真正命令,而是按进程方式来调度运行的内核线程,有时候这些进程的名字以一个斜线加一个数字结尾,比如 [ksoftirqd/3],这个数字表明该线程在哪个处理器上运行,在多处理器的系统上会出现这种有意思的情况。
ps aux 命令输出的解释
字段 | 内容 |
---|---|
USER | 进程的属主的用户名 |
PID | 进程 ID |
%CPU | 该进程正在使用的 CPU 百分比 |
%MEM | 该进程正在使用的实际内存百分比 |
VSZ | 进程的虚拟大小 |
RSS | 驻留集的大小(内存中页的数量) |
TTY | 控制终端的 ID |
STAT | 当前进程的状态: D = 等待磁盘 R = 在运行或可运行 S = 在睡眠(<20s) T = 被跟踪或者被停止 W = 页面调度(2.6.xx 内核以上) X = 死亡(正常情况下是看不到这个状态的) Z = 僵死进程 附加标志: < = 高优先级 N = 低优先级 L = 有些页面被锁在内存里 s = 进程是会话的先导进程 l = 进程是多线程 + = 进程处于前台进程组 |
START | 启动进程的时间 |
TIME | 进程已经消耗掉的 CPU 时间 |
COMMAND | 命令的名称和参数 |
另一组有用的选项是 lax,它提供了技术性更强的信息。
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND 4 0 1 0 20 0 2880 1712 poll_s Ss ? 0:00 /sbin/init 1 0 2 0 20 0 0 0 kthrea S ? 0:00 [kthreadd] 1 0 3 2 20 0 0 0 run_ks S ? 0:00 [ksoftirqd/0] 1 0 4 2 -100 - 0 0 cpu_st S ? 0:00 [migration/0] 5 0 5 2 -100 - 0 0 watchd S ? 0:00 [watchdog/0] 1 0 6 2 -100 - 0 0 cpu_st S ? 0:00 [migration/1] 1 0 7 2 20 0 0 0 run_ks S ? 0:00 [ksoftirqd/1] 5 0 8 2 -100 - 0 0 watchd S ? 0:00 [watchdog/1] 1 0 9 2 -100 - 0 0 cpu_st S ? 0:00 [migration/2] 1 0 10 2 20 0 0 0 run_ks S ? 0:00 [ksoftirqd/2] 5 0 11 2 -100 - 0 0 watchd S ? 0:00 [watchdog/2] 1 0 12 2 -100 - 0 0 cpu_st S ? 0:00 [migration/3] 1 0 13 2 20 0 0 0 run_ks S ? 0:00 [ksoftirqd/3]
ps lax 的输出包括父进程 ID(PPID)、谦让值(NI)字段以及进程正在等待的资源(WCHAN)。
top: 更好地监视进程
由于 ps 这样的命令只提供系统过去时间的一次性快照,因此,要获得系统上正在发生事情的“全景”往往是非常困难的。top 命令对活动进程以及其所使用的资源情况提供定期更新的汇总信息。
/proc 文件系统
Linux 版的 ps 和 top 命令都从 /proc目录获取进程的状态信息,内核把有关系统状态的各种有意义的信息都放在这个伪目录里。虽然这个目录叫做/proc(下面的文件系统类型也叫做“proc”),但是它里面的信息却并局限于进程信息——内核产生的所有状态信息和统计数据都在这里。用户也可以通过向/proc 下的适当文件写入数据的方法来修改某些参数。
进程特有的信息都分别被放到了按 PID 起名字的子目录里。例如,/proc/1一定是包含 init 信息的目录。下表列出了各个进程最有用的文件,用户应该用 cat 或者 more 命令去看这些文件:
文件 | 内容 |
---|---|
cmdline | 进程完整命令行(以 null 分隔) |
cwd | 链到进程当前目录的符号链接 |
environ | 进程的环境变量(以 null 分隔) |
exe | 链到正被执行的文件的符号链接 |
fd | 子目录,其中包含链到每个打开文件的描述符的链接 |
maps | 内存映射信息(共享段、库等) |
root | 链到进程的根目录(由 chroot 设置)的符号链接 |
stat | 进程的总体状态信息(ps 最擅长解析这些信息) |
statm | 内存使用情况的信息 |
在 cmdline 和 environ 文件里的各个部分用空字符(null)而不是换行符(newline)分隔。用户可以借助命令
过滤掉这些文件的内容,使之可读性更好。
strace: 追踪信号和系统调用
将 strace 附在一个活动的 pid 进程上