线程创建失败90%源于ulimit -u限制,它同时约束用户级进程与线程总数;需优先调大ulimit -u,并同步检查pid_max和threads-max,三者取最小值决定真实上限,任一未调到位仍报“Resource temporarily unavailable”。

线程创建失败,90% 不是内核参数问题,而是 ulimit -u 卡住了——它同时限制进程 + 线程总数,Java、Node.js 服务一开几百线程就爆,必须优先调大。
查清哪一层真在卡住线程创建
别一报 java.lang.OutOfMemoryError: unable to create new native thread 就改内核。先跑这四条命令快速定位:
-
ps -eLf | wc -l—— 当前总线程数 -
ulimit -u—— 当前 shell 用户级上限(普通用户常为 1024) -
cat /proc/sys/kernel/threads-max—— 内核全局线程总数上限 -
cat /proc/sys/kernel/pid_max—— PID 总量天花板,threads-max不能超过它
如果 ps -eLf | wc -l 接近 ulimit -u 输出值,瓶颈就在用户级;接近 pid_max,说明内核 PID 资源耗尽;接近 threads-max 且 pid_max 更大,才动内核参数。
改 ulimit -u:最常见生效点,但容易配错
这是 Java、Python 多线程服务卡死的主因——进程启动时直接继承 shell 的 ulimit -u 值,而它管的是“进程 + 线程”总数。
- 临时生效(当前终端及所有子进程):
ulimit -u 65535 - 永久生效(新登录会话):写入
/etc/security/limits.d/90-nproc.conf,内容为:* soft nproc 65535* hard nproc 65535 - systemd 服务不读
limits.conf,必须在 service 文件里加:[Service]LimitNPROC=65535 - Docker 容器需显式传参:
docker run --ulimit nproc=65535:65535
注意:su - user 切换用户后需重新登录才加载 PAM limits;su user(不带 -)不会触发,配置无效。
Linux AI 服务器 — 将 Linux 服务器转换为本地 AI 推理集群。使用 systemd、NVIDIA CUDA 实现无头 Linux AI,零 GUI 开销。
调 /proc/sys/kernel/threads-max 和 pid_max:改前必查依赖
threads-max 是内核能支撑的全局线程总数,但它受 pid_max 硬性约束——写入值若大于 pid_max,会静默失败并报 Invalid argument。
- 先确认:
cat /proc/sys/kernel/pid_max,若小于目标值,先调大:sudo sysctl -w kernel.pid_max=4194304 - 再设
threads-max(例如 2097152):echo 2097152 | sudo tee /proc/sys/kernel/threads-max - 永久配置写入
/etc/sysctl.d/99-thread-limit.conf:kernel.threads-max = 2097152
然后执行sudo sysctl --system - RHEL/CentOS 7+ 可能还需:
sudo systemctl restart systemd-sysctl
容器环境里修改只对当前 PID namespace 生效,宿主机和其他容器不受影响。
验证是否真正生效
改完不能只看配置文件,必须验证进程实际继承的值:
- 新开终端执行
ulimit -u,确认输出是预期值 - 查具体进程:
prlimit -n $(pidof java),看MAX processes行 - 检查内核参数:
sysctl kernel.pid_max kernel.threads-max - 注意:三者(
ulimit -u、pid_max、threads-max)取最小值才是真实上限,任何一个没调到位,线程照样创建失败
最容易被忽略的是 systemd 服务完全绕过 limits.conf,以及容器未显式传 --ulimit 参数——这两处不单独处理,改了也白改。

















