僵死进程是子进程终止后父进程未调用wait()回收所致,仅占pid和少量内核内存,不占cpu/内存,危害在于耗尽pid导致无法创建新进程。

信号丢失本身不会直接导致“僵死异常”,但会引发看似僵死的行为——比如子进程退出后父进程收不到 SIGCHLD,大量僵尸进程堆积;或服务该响应 SIGTERM 却无反应,表现为假死。这类问题本质是信号未被正确递送或处理,排查需聚焦“信号是否发出→是否抵达→是否被处理”三层断点。
确认信号是否实际产生并投递
很多“信号没起作用”的错觉,其实源于信号根本没发出去,或发给了错误进程:
- 用 kill -0
验证目标进程是否存在且可接收信号(不真发送,只做权限与存在性检查) - 对关键信号(如 SIGCHLD、SIGHUP)触发源做日志或 strace 跟踪:比如在父进程中 strace -e trace=clone,wait4,rt_sigprocmask -p
,观察子进程退出时是否触发 wait4() 或信号相关系统调用 - 检查 /proc/
/status 中的 SigQ 字段:格式为 x/y,其中 x 是当前队列中待处理信号数,y 是信号队列上限;若 x 持续为 0 但应有信号(如子进程已退出),说明信号压根没生成或被丢弃
检查信号是否被阻塞或忽略
信号可能已送达,却被进程主动屏蔽或默认忽略:
- 查看 /proc/
/status 的 SigBlk(阻塞掩码)和 SigIgn(忽略掩码)字段,转为二进制后比对对应信号位(如 SIGCHLD=17,查第 17 位是否为 1) - 普通信号(1–31)不排队,同一信号在未处理完前重复发送会被合并。若看到频繁 fork/exit 但 SigQ 始终 ≤1,就属典型丢失——不是内核丢了,而是机制上就不保留多次
- SIGCHLD 默认被忽略,必须显式注册 handler 才能捕获;若代码里只调了一次 signal(SIGCHLD, handler),但 handler 内未循环 wait,或 handler 执行中又被中断重入,也会造成“收到却没清干净”
验证信号处理逻辑是否真正执行
即使信号抵达且未被阻塞,handler 也可能因设计缺陷而失效:
- 用 strace -p
-e trace=rt_sigaction,rt_sigreturn,kill 观察信号注册、抵达和返回全过程。重点看是否有 rt_sigaction(SIGCHLD, {...}, ...) 注册,以及后续是否出现 --- SIGCHLD {si_signo=SIGCHLD, ...} --- 和对应的 rt_sigreturn - 常见陷阱:handler 中调用非异步信号安全函数(如 printf、malloc),导致死锁或崩溃,表面看就是“信号来了但没反应”
- 若使用 signal() 而非 sigaction(),某些系统下 handler 执行完会自动重置为默认行为(即再次忽略),导致第二次 SIGCHLD 来临时无处理函数
区分僵死类型,避免误判
“僵死”常被混用,但信号问题对应的是不同状态,需精准识别:
- 进程状态为 Z(zombie):明确指向 SIGCHLD 处理失败,父进程未 wait
- 进程状态为 D(uninterruptible sleep):通常卡在内核态(如磁盘 IO),信号无法递送,此时查 /proc/
/stack 看内核栈,而非怪信号丢失 - 进程状态为 R 或 S 但无响应:可能是信号 handler 死循环、或业务逻辑阻塞在不可中断操作,需结合 strace 和 cat /proc/
/wchan 判断等待点











