更新#

更新#

我在新启动的 bash 中运行以下命令(没有任何先前的子进程)

$ prlimit --pid $BASHPID --nproc=20:

这给了我雪崩般的

bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: Resource temporarily unavailable

我想知道是20太低了,还是程序错误?这里发生了什么?

我知道 bash 有一个内部内置ulimit调用,但为什么prlimit不起作用

更新#

bash 内置函数也ulimit产生相同的结果

$ ulimit -Su 20
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: retry: No child processes
bash: fork: Resource temporarily unavailable
bash: wait_for: No record of process 7527
bash: fork: retry: No child processes
bash: fork: retry: No child processes

这个问题的答案可能与如何理解 ulimit RLIMIT_NPROC 有关。好像既绑定了UID又绑定了PID?

也许有人也能够深入了解区分两种不同错误消息No child processesResource temporarily unavailable

答案1

您误解了进程限制的工作原理。prlimit --nproc又名RLIMIT_NPROC又名ulimit -u是整个用户的最大进程数。如果您已经有 20 个正在运行的进程,并且将限制设置为 20,则无法创建任何新进程。重要的是有多少进程以您的用户身份运行,它们的父进程是谁或者它们的限制设置是什么并不重要。

微妙之处在于,虽然限制是全局的,但它仅适用于设置它的进程。因此,如果您有 18 个进程正在运行,并且prlimit --nproc 20 bash在一个终端和另一个终端中运行prlimit --nproc 30 bash,则第一个 bash 无法创建任何子进程,但第二个 bash 可以创建更多子进程,直到总共 30 个(无论它们是否已启动)无论是否来自那场狂欢)。

如果将某个进程的限制设置为 1,则该进程根本无法 fork,但其他进程仍然可以 fork。如果您在登录脚本中将限制设置为某个数字,则该数字适用于您的进程(不读取登录脚本而启动的进程除外,例如从 cron 作业启动的进程)。其他情况可能会令人困惑。

从实现的角度来描述这一点是最简单的。该限制仅在执行系统调用时读取fork。当进程调用时fork,内核会计算数量进程以同一用户身份运行。如果调用进程的 NPROC 限制小于或等于然后调用被拒绝并出现错误EAGAIN(“资源暂时不可用”,即“重试”)。

在您的情况下,您可能已经有至少 20 个进程正在运行,并且您.bashrc运行了多个子进程(或者更确切地说,由于已达到进程限制而无法运行它们)。

您会看到两条不同的消息,因为当错误为 时,bash 尝试分叉多次EAGAIN。第一次它显示一条消息说它正在重试,最后它显示一条消息说它已放弃。

准确地说,是内核线程。
²这个系统调用在Linux上被调用clone

答案2

底线是-nproc设置可运行项目的限制(即线程和进程,并且由于我臃肿的 .bashrc 内容,需要超过 20 个线程,至少这是我的假设,因为

像这样开始新的bash之后

$ bash --noprofile --norc

这是可能的

bash-4.3$ ulimit -Su 1
bash-4.3$ echo 1
1
bash-4.3# echo 1 &
bash: fork: retry: No child processes

那就是一个线程就足够了,哇!

相关内容