You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Docker下/bin/sh会向java进程传播SIGTERM却不对sleep进程生效?

现象解释

前置核心规则

  • Linux 内核会对 PID 1 进程做特殊信号处理:所有未被进程显式注册处理函数的信号,都会被直接丢弃,不会执行普通进程对应的默认动作(比如 SIGTERM 的默认动作是终止进程,对未注册对应 handler 的 PID 1 进程完全无效)。
  • POSIX 标准的 sh 实现(如 dash、busybox sh 等,非 bash)执行 sh -c "命令串" 时,存在 exec 优化逻辑:如果命令串是单个无后续执行逻辑的简单命令,sh 会直接调用 exec() 系统调用,将自身进程镜像完全替换为目标命令的进程,目标命令继承 sh 原有的 PID,原 sh 进程不复存在。

两种场景的差异原因

场景1:/bin/sh -c java ... 信号传递正常

你的 Java 启动命令符合 sh -c 的 exec 优化条件,sh 执行时直接把自身替换为 Java 进程,此时 Java 就是 PID 1 进程。
Java 虚拟机默认会主动注册 SIGTERM 信号的处理函数,收到信号后会触发所有注册的 shutdown hooks 执行,完成清理逻辑后再正常退出,因此你会观察到信号传递正常、钩子正常执行的现象。

场景2:/bin/sh -c sleep ... 无法被 SIGTERM 终止

该场景存在两种可能的原因:

  1. 符合 exec 优化条件:sh 直接替换为 sleep 进程,sleep 作为 PID 1 运行。sleep 程序本身没有注册 SIGTERM 信号的处理函数,按照 PID 1 的信号规则,收到的 SIGTERM 会被内核直接丢弃,不会触发终止进程的默认动作,sleep 会一直运行直到计时结束。
  2. 不符合 exec 优化条件:如果你的命令串带了后续执行逻辑(比如 /bin/sh -c "sleep 3600; echo finish"),sh 无法直接替换为 sleep 进程,会 fork 出子进程运行 sleep,自身作为 PID 1 等待子进程退出。而 sh 本身没有注册 SIGTERM 的处理函数,收到信号后被内核直接丢弃,既不会自身退出,也不会主动给子进程 sleep 转发信号,因此 sleep 会一直运行。

内容的提问来源于stack exchange,提问作者Flame239

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 21:54:02