Linux 3.12.14系统中如何避免crond -l 9衍生的sh僵尸进程?
解决crond父进程导致的sh僵尸进程问题(无需重启crond)
碰到这种crond作为父进程的sh僵尸进程,核心原因是子进程(sh)退出后,父进程(crond)没有调用wait()/waitpid()回收其退出状态,导致进程残留为僵尸状态。下面分两步解决:先清理现有僵尸,再预防新的僵尸产生。
一、立即清理现有sh僵尸进程
僵尸进程本身已经停止运行,无法直接用kill终止,但可以触发其父进程(crond)主动回收它们:
- 首先找到crond的PID:
ps aux | grep crond | grep -v grep - 给crond发送
SIGCHLD信号,通知它回收所有已退出的子进程:kill -SIGCHLD <crond_pid>
这个信号只会让crond处理子进程的退出状态,不会重启或中断crond的正常运行,完全安全。
二、预防新的sh僵尸进程产生
1. 优化crontab定时脚本
僵尸进程的源头往往是脚本本身的执行逻辑问题,先检查你的定时脚本:
- 避免在脚本中后台执行任务(加
&):crond本身就是后台调度器,不需要在脚本里给命令加&。如果脚本里有command &这类后台任务,会导致sh进程提前退出,而crond可能无法及时回收sh的状态。如果必须后台执行,在脚本结尾加上wait命令,确保sh等待所有后台子进程完成后再退出:# 示例脚本:等待所有后台任务完成 your_command & wait # 这行确保sh不会提前退出 - 避免脚本产生孤儿进程:如果脚本中必须启动长期运行的后台进程,使用
disown命令让进程脱离sh的控制,这样sh退出时,后台进程的父进程会切换为init(或systemd),由系统进程负责回收,不会导致sh变成僵尸:your_long_running_command & disown %1
2. 给crond设置子进程收割属性
Linux内核从3.4版本开始支持PR_SET_CHILD_SUBREAPER属性,设置后crond会成为子进程的“收割者”,接管其孙子进程的退出状态,避免因脚本内的子进程问题导致sh僵尸:
- 执行以下命令给crond进程设置该属性:
prctl -n PR_SET_CHILD_SUBREAPER -v 1 -p <crond_pid>
这个设置是临时的,系统重启后会失效,可以把这条命令加到开机启动脚本中(比如/etc/rc.local),确保每次开机后自动生效。
3. 检查crond版本与配置
你的系统内核是3.12.14,对应的crond可能存在已知的僵尸进程bug(比如旧版本的vixie-cron或cronie):
- 查看crond版本:
crond -V - 如果是版本bug,后续可以在业务低峰期升级crond并重启,但当前无需重启即可通过上面的方法缓解问题。
总结
先发送SIGCHLD清理现有僵尸,再通过脚本优化和PR_SET_CHILD_SUBREAPER设置预防新僵尸,完全不需要重启crond就能解决问题。
内容的提问来源于stack exchange,提问作者mselvara1982
相关产品推荐
相关产品推荐

