Linux进程异常终止排查_信号机制分析【技巧】

3次阅读

进程被 kill -9 杀掉后找不到日志,因为 SIGKILL 不可捕获,进程立即终止且不执行任何清理逻辑;需排查 oom_killer、容器运行时、人为 kill 或 systemd 超时等来源。

Linux 进程异常终止排查_信号机制分析【技巧】

进程被 kill -9 杀掉后 为什么 找不到日志?

因为 SIGKILL(信号 9)无法被捕获、阻塞或忽略,进程在收到该信号后立刻终止,连清理逻辑(比如写日志、关闭文件描述符)都不会执行。所以你查 systemd 日志、应用自身日志、甚至 strace 跟踪都看不到“主动退出”痕迹。

真正要查的不是“它怎么退出”,而是“谁发了 SIGKILL”。常见来源有:

  • oom_killer:内存耗尽时内核主动干掉进程,会在 dmesg 中留下记录,关键词是 Out of memory: Kill process
  • 容器运行时(如 dockerdcontainerd)因内存 limit 触发 OOM,也会走内核 oom_killer 流程
  • 人为执行了 kill -9,但没留操作记录;可检查 auditd 日志(/var/log/audit/audit.log)中 SYSCALL arch=c000003e syscall=62 success=yes(对应 kill 系统调用)
  • systemdTimeoutStopSec 超时后 fallback 到 SIGKILL,此时 journalctl -u xxx.service 会显示 Stopping timed out. Killing.

如何确认是不是 oom_killer 干的?

直接看内核环形缓冲区:

dmesg -T | grep -i "killed process"

注意时间戳是否与进程终止时间吻合。如果匹配,你会看到类似:

[Wed Jun 12 14:22:35 2024] Out of memory: Kill process 12345 (python3) score 892 or sacrifice child

关键字段解释:

  • score 是 oom_score,数值越高越可能被选中;可通过 cat /proc/12345/oom_score 查看当前值
  • sacrifice child 表示杀的是子进程而非主进程,说明父进程还在,但某个子任务吃光了内存
  • 该日志只存在于内核 log,不会进 journald,也不会写入任何用户空间日志文件

进程收到 SIGTERM 却没响应?检查 signal handler 是否被覆盖

很多程序用 signal()sigaction() 注册 SIGTERM 处理函数,但第三方库(尤其是 C 扩展或嵌入式运行时)可能重置信号行为。典型表现是:手动 kill 后进程卡住不退出。

验证方式:

  • strace -p -e trace=signal 观察是否收到 SIGTERM,以及是否调用了 rt_sigaction 设置 handler
  • 检查进程是否屏蔽了 SIGTERMcat /proc//status | grep SigBlk,输出是十六进制掩码,需转换——SIGTERM 对应 bit 15(从 0 开始计),若该位为 1 则被屏蔽
  • Python 进程尤其容易出问题:若主线程已退出,而子线程仍在运行且未设 daemon=TrueSIGTERM 可能无法触发 atexitsignal.signal() 注册的回调

用 strace 捕获信号传递全过程

strace 是唯一能在用户态看到“信号到达→处理→返回”的 工具,但默认不显示信号细节。正确用法是:

strace -e trace=signal,process -f -p 

其中:

  • signal 跟踪 killsigreturnrt_sigprocmask 等信号相关系统调用
  • process 跟踪 forkexecveexit_group,便于关联父子进程行为
  • -f 必须加,否则子线程 / 子进程的信号事件看不到

典型输出片段:

--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=1001, si_uid=0} --- rt_sigreturn({mask=[]}) = 0 exit_group(143)                     = ?

这表示进程收到了用户态发起的 SIGTERM,执行了信号返回,然后调用 exit_group 正常退出。如果只有第一行而没有后续,说明 handler 没有调用 exit 或被阻塞了。

信号调试最难的一点:它发生在内核和用户 交界处,既不能靠源码断点(handler 可能不在你的代码里),也不能靠日志(log 写入本身可能被信号中断)。必须用 straceperf trace -e syscalls:sys_enter_kill 这类内核级观测手段。

星耀云
版权声明:本站原创文章,由 星耀云 2026-01-06发表,共计1823字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources