我在新启动的 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 processes
和Resource 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
那就是一个线程就足够了,哇!