僵尸进程的数量有上限吗?

僵尸进程的数量有上限吗?

我曾经使用 HP-UX 系统,老管理员告诉我系统上可以拥有的僵尸进程数量有上限,我相信是 1024。

  • 这是一个硬事实上限吗?我认为你可以有任意数量的僵尸,就像你可以有任意数量的进程一样......?
  • 不同发行版的价值是否不同?
  • 如果我们达到上限并尝试创建另一个僵尸会发生什么?

答案1

我没有可用的 HP-UX,而且我从来都不是 HP-UX 的忠实粉丝。

看来在 Linux 上,每个进程或可能每个用户对存在的子进程数量有限制。您可以使用limit内置的 Zsh 来查看它(似乎类似于ulimit -ubash):

1002 % limit
cputime         unlimited
filesize        unlimited
datasize        unlimited
stacksize       8MB
coredumpsize    0kB
memoryuse       unlimited
maxproc         16136
  ...

这是在 Arch Linux 笔记本电脑上。

我写了一个小程序来测试这个限制:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

volatile int sigchld_cnt = 0;

voida
sigchld_hdlr(int signo)
{
        ++sigchld_cnt;
}

int
main(int ac, char **av)
{
        int looping = 1;
        int child_cnt = 0;
        int status;

        signal(SIGCHLD, sigchld_hdlr);

        printf("Parent PID %d\n", getpid());

        while (looping)
        {
                switch (fork())
                {
                case 0:
                        _exit(0);
                        break;
                case -1:
                        fprintf(stderr, "Problem with fork(), %d children: %s\n",
                                child_cnt, strerror(errno));
                        looping = 0;
                        break;
                default:
                        ++child_cnt;
                        break;
                }
        }

        fprintf(stderr, "Sleeping, forked %d child processes\n", child_cnt);
        fprintf(stderr, "Received %d sigchild\n", sigchld_cnt);
        sleep(10);

        looping = 1;
        do {
                int x = wait(&status);

                if (x != -1)
                        --child_cnt;
                else if (errno != EINTR) {
                        fprintf(stderr, "wait() problem %d children left: \%s\n",
                                child_cnt, strerror(errno));
                        looping = 0;
                }
        } while (looping);

        printf("%d children left, %d SIGCHLD\n", child_cnt, sigchld_cnt);

        return 0;
}

召唤足够多的次数来“收集”所有僵尸是非常困难的wait(2)。另外,收到的 SIGCHLD 信号的数量永远不会与分叉的子进程的数量相同:我相信 Linux 内核有时会为多个退出的子进程发送 1 SIGCHLD。

无论如何,在我的 Arch Linux 笔记本电脑上,我分叉了 16088 个子进程,这一定是僵尸进程的数量,因为该程序不会wait(2)在信号处理程序中执行系统调用。

在我的 Slackware 12 服务器上,我有 6076 个子进程,这与maxproc 6079.我的用户 ID 有 2 个其他进程正在运行,sshd还有 Zsh。加上上面程序的第一个非僵尸实例,结果为 6079。

系统fork(2)调用失败并出现“资源暂时不可用”错误。我没有看到任何其他证据表明哪些资源不可用。如果我在 2 个不同的 xterm 中同时运行我的程序,我确实会得到一些不同的数字,但它们加起来的数字与我在一个 xterm 中运行它时的数字相同。我假设它是进程表条目、交换或某些系统范围的资源,而不仅仅是任意限制。

我现在没有其他东西可以尝试。

答案2

我不知道 HP-UX 的限制是什么。不过,我可以告诉您,逻辑实现是拥有一个具有最大大小的进程表。理论上,进程表条目的总数受到进程 ID 范围的限制,但大多数实现都有表的大小限制,这会产生更小的最大值。大多数 Unix 变体也对每个用户的进程数量有限制;您可以通过在 bash 中运行来查看限制ulimit -u

我不希望 UNIX 系统对僵尸有单独的限制,而不是对进程 ID 的数量(包括实际进程和僵尸)有单独的限制。因此,当进程死亡并成为僵尸进程时,这不会影响限制:资源(进程表中的条目)在进程分叉时分配,并在进程回收时释放。

答案3

我认为你可以有任意数量的僵尸,就像你可以有任意数量的进程一样......?

僵尸进程最终是一个处于特殊状态的进程,然后僵尸进程受到进程表的可用性和大小的限制,至于常规的流程。

不同发行版的价值是否不同?

当然,还有许多其他参数。您不应该依赖特定的大小,或者它是否足够大以容纳许多僵尸进程。如果僵尸太多,那么解决方案就不是一张大桌子,因为它最终会满的。僵尸进程本身并不坏,但是累积太多僵尸进程表明存在允许僵尸进程的“行为不良”程序。

如果我们达到上限并尝试创建另一个僵尸会发生什么?

一旦进程表充满了常规进程和僵尸进程,就无法创建新的常规进程,即使系统有足够的资源(内存、处理器等)。唯一缺少的资源只是进程表中的一个条目。已经在运行的程序——即使是那些“表现良好”的程序——在需要创建子进程时也会开始失败。新程序无法启动,甚至运行单个命令也会失败。

相关内容