排查进程因信号退出需先确认退出码(如137为sigkill)、查systemd日志和dmesg,再结合strace、core dump、waitpid等定位信号来源,最后通过检查系统调用返回值、启用心跳、规范fd管理等根治。

排查进程因特定信号退出,核心是确认“谁发的、为什么发、在哪发的”。不能只盯着信号本身,而要顺藤摸瓜查触发条件。
先确认是不是这个信号导致退出
很多崩溃表面像信号问题,实际是其他原因。第一步必须验证:
- 查退出码:运行后立刻执行 echo $?。130 是 SIGINT,137 是 SIGKILL,141 是 SIGPIPE,139 是 SIGSEGV——这些数字能快速锁定信号编号
- 看 systemd 日志(如果服务由它管理):systemctl status your-service 和 journalctl -u your-service -n 50,里面会明确写 “Killed by signal SIGxxx” 或 “Process exited with code X”
- 检查内核日志:dmesg -T | tail -20,尤其关注 OOM Killer(SIGKILL)、pipe broken、segfault 等关键词
定位信号来源和触发点
信号不是凭空来的,它一定对应某个具体动作或状态变化:
- SIGPIPE:一定是往已关闭的 socket、管道或 FIFO 写数据。用 strace -e trace=write,send,close -p $pid 捕获实时系统调用,重点看最后一次 write/send 是否返回 -1 且 errno=32
- SIGSEGV / SIGFPE:来自 CPU 硬件异常。优先检查是否生成 core 文件(ulimit -c 确认开启),然后用 gdb your-bin core 查看崩溃栈
- SIGKILL(退出码 137):无法捕获,也不留痕迹。大概率是 OOM Killer 所为,查 dmesg -T | grep "killed process";也可能是手动 kill -9 或容器 runtime 强制终止
- SIGTERM / SIGHUP:通常是人为主动发送,查操作记录、定时任务、部署脚本或父进程逻辑(比如 supervisord、systemd 的 RestartSec 配置)
验证与临时缓解
不改代码也能快速缩小范围:
- 启动前忽略该信号测试:Shell 中加 trap '' PIPE(对 SIGPIPE),或 C 中 signal(SIGPIPE, SIG_IGN)。若不再退出,基本可锁定
- 用 waitpid() 在父进程中捕获子进程退出状态:调用 WIFSIGNALED(status) 判断是否信号终止,再用 WTERMSIG(status) 提取具体信号号
- 多线程程序要注意:仅在主线程调 signal() 不生效,需用 pthread_sigmask() 在所有线程初始化时屏蔽
长期修复的关键习惯
忽略信号只是防崩,不是根治:
- 所有 write()/send()/read() 调用后必须检查返回值:等于 0 表示对端关闭,小于 0 且 errno 是 EPIPE/ECONNRESET 就该主动 close 并清理资源
- 网络连接务必配合 SO_KEEPALIVE 或应用层心跳,避免复用断连连接
- 子进程管理要规范:fork 后及时 close 不需要的 fd,避免管道读端残留导致 SIGPIPE
- 关键服务启用 core dump,并配置 /proc/sys/kernel/core_pattern 把 core 文件存到易查位置











