父进程是1号进程产生大量的僵尸进程的解决方案

实际记录一次在使用Dockerfile构建镜像和容器的时候出现的问题

前景:

封装chrome和crawler进行一个简单的爬虫功能

Dockerfile的EntryPoint是java -jar 启动jar命令,当你访问api的时候会使用Runtime.exec()方法拼装url自动进行爬取访问。

定位问题:

调用chrome会出现大量的chrome进程,同时任务结束的时候调用ps -aux 发现大量的进程stat状态为Z,也就是处于僵尸状态,调用ps -ef 发现僵尸进程的父进程Id为1

学习过程:

僵尸进程:stat状态为Z,已经调用过exit方法,但是还是占用一部分的系统资源无法释放。一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit, 它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。

kill 命令:kill -9 向进程发送结束命令,让进程调用exit方法来进行结束。

我在学到这两个东西的时候以为我可以使用kill来对僵尸进程进行清理,但是我多次尝试并没有成功,最后发现僵尸进程已经处于死亡状态了,kill没办法再次杀死这个进程了。继续学习

僵尸进程产生的原因:子进程执行完毕留下了一个需要父进程收尸的一个退出状态结构,如果他的父进程没安装 SIGCHLD 信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果父进程也结束了,这些子进程会自动过继给init进程进程定期的回收。

学到这里以为搜索网上的处理方法,发现大多的都是让我杀死僵尸进程的父进程,过继给init进程进行回收,但是我发现他们的父进程就是init进程,这可把我整懵了,开始思考

思考过程:

容器重启:docker创建的容器会自动将启动的cmd或者enterpoint作为init进程,所以你想要杀死这个进程就必须将整个容器重启,但是我又不想重启整个容器,因为这样我虽然能解决一些问题,但是我相当于是走了一个捷径并没有解决根本问题。

继续思考,既然我杀不死这些僵尸进程,那我就只能从源头解决了,那就是不让父进程生成僵尸进程,然后我就懵了,因为chrome的默认命令产生的僵尸进程,我也不能修改chrome源码啊!

寻求帮助:

在我向公司的大佬提出问题的时候大佬向我提出了一个叫tini的东西

    GitHub地址:https://github.com/krallin/tini

使用方法地址里面已经有了,可以说是非常好用直接解决所有问题,但是我发现他好像在我的执行命令里面增加一些进程。然后fock()出来的都是他的子进程,所以只要直接管理他们的父进程然后回收这些子进程就可以了。原理我也不太懂,慢慢了解,学习的路程永远是快乐的。

原文地址:https://www.cnblogs.com/frank9571/p/14327718.html