我有一个生产单元,其中 java 进程已成为僵尸并在那里停留了一段时间。如果设备重新启动,则会被清除。但是,该单元未重新启动,并且另一个 java 进程已启动并正在运行。如果这个僵尸状态保持原样而不清除,会有什么问题吗?它会以任何方式影响(性能或缓慢)吗?
答案1
僵尸进程不会对性能或速度产生任何影响,因为僵尸进程不会占用任何系统资源。
笔记:- 实际上,它仍然使用 PID(这是一种有限的资源),并且仍然分配进程的内核数据结构。通常,这并不重要,但在内存非常有限的系统上,内核内存使用量可能会很大。
僵尸进程引起的问题
每个僵尸进程都保留其进程 ID。 Linux 系统的进程 ID 数量是有限的 –32767默认情况下在 32 位系统上。如果僵尸进程以非常快的速度累积,则整个可用 PID 池最终将分配给僵尸进程,从而阻止其他进程启动。
笔记:在64位系统上,可以增加最大PID,参见https://unix.stackexchange.com/a/16884/170373
然而,一些僵尸进程徘徊是没有问题的——尽管它们确实表明您的系统上的父进程存在错误。
解释:
当一个进程在 Linux 上死亡时,它并不会立即从内存中删除——它的进程描述符仍然保留在内存中。
进程的状态变为EXIT_ZOMBIE
,并通过该信号通知进程的父进程其子进程已死亡SIGCHLD
。
然后,父进程应该执行 wait() 系统调用来读取死亡进程的退出状态和其他信息。这允许父进程从死亡进程获取信息。调用 wait() 后,僵尸进程就会从内存中完全删除。
这通常发生得非常快,因此您不会看到系统上累积僵尸进程。但是,如果父进程没有正确编程并且从不调用 wait(),则其僵尸子进程将保留在内存中,直到被清除。
解决:
您无法杀死僵尸进程,因为您可以使用 SIGKILL 信号杀死正常进程 - 僵尸进程已经死亡。
杀死僵尸进程的一种方法是向父进程发送 SIGCHLD 信号。该信号告诉父进程执行 wait() 系统调用并清理其僵尸子进程。使用kill命令发送信号,将下面命令中的pid替换为父进程的PID:
kill -s SIGCHLD pid
当创建僵尸进程结束时,init 继承僵尸进程并成为它们的新父进程。 (init 是 Linux 上启动时启动的第一个进程,分配的 PID 为 1。)
笔记:-从 Linux 3.4 开始,进程可以使用 PR_SET_CHILD_SUBREAPER 选项发出 prctl() 系统调用,因此它们(而不是进程 #1)将成为其孤立后代进程的父进程。参考: https://unix.stackexchange.com/a/177361/5132
然后,INIT 执行 wait() 系统调用来清理其僵尸子进程,因此 init 可以快速处理僵尸进程。关闭父进程后可以重新启动它。
答案2
大多数情况下,僵尸并不是一个大问题。它们是一个“死”进程,不占用 CPU 时间和任何分配的内存应该在死亡前已被该过程释放。他们实际占用的唯一资源是进程列表中的条目。根据您的系统,您可以拥有允许的最大线程数,而拥有僵尸可以让您无缘无故更快地达到此限制。
然而:僵尸通常是由于糟糕/有缺陷的代码而出现的,程序员在其中忘记检查其子进程的状态。这可能是有意的,但通常不是有意的。错误/有缺陷的代码通常也会以错误的方式处理内存 特别的方式,以及不是释放一些分配的资源。如果是这种情况,这些资源将保持分配给僵尸,直到它完全终止。
编辑:如果进程是一个java程序,不释放内存应该不是问题,因为java垃圾收集器会处理一切。