如何指定子进程的父进程 无需修改Java代码或新增命名空间
问题解决方案
你场景中java2最终被init进程收养的核心原因是:java1启动java2后提前退出,导致java2成为孤儿进程,默认规则下PID namespace内的孤儿进程会被init进程接管。无需修改Java代码、无需新增命名空间即可实现需求,可通过Linux自带的子收割者机制实现。
核心原理
Linux内核自3.4版本引入了PR_SET_CHILD_SUBREAPER进程属性,被设置该属性的进程会成为「子收割者」,其所有后代孤儿进程都会被它接管,而非直接上报给PID namespace的init进程。
操作步骤
方案一:复用当前bash作为公共父进程(最简实现)
- 如果系统没有预装prctl,先安装依赖包:Debian/Ubuntu系执行
apt install procps-ng,RHEL/CentOS系执行yum install procps-ng - 启动java1前,在当前bash窗口执行命令:
prctl --set child_subreaper 1,将当前bash设置为子收割者 - 正常从当前bash启动java1,此时java1的父进程为当前bash
- java1启动java2后即使java1退出,java2作为孤儿进程会被当前bash接管,两个Java进程的父进程均为该bash(非init进程)
方案二:使用独立中间进程作为公共父进程(不影响bash生命周期)
如果不希望bash作为公共父进程,可以单独启动一个轻量常驻进程作为父进程:
- 后台启动无业务逻辑的常驻进程,执行:
nohup tail -f /dev/null &,记录返回的进程PID为$MIDDLE_PID - 给该中间进程设置子收割者属性:
prctl --set child_subreaper 1 -p $MIDDLE_PID - 用该中间进程启动java1,示例命令:
nsenter -t $MIDDLE_PID -p bash -c "java -jar 你的java1包路径.jar &" - 后续java1启动java2后若java1退出,java2会被该中间进程接管,两个Java进程的父进程均为这个独立中间进程
结果验证
执行ps -o ppid,pid,cmd -C java即可查看两个Java进程的父进程ID,确认二者父进程ID一致且不为1(init进程PID固定为1)即可。
内容的提问来源于stack exchange,提问作者Vitaliy Ivanov
相关产品推荐
相关产品推荐

