确认系统卡在哪个限制需查三处:cat /proc/sys/kernel/pid_max看全局PID池上限,ulimit -u看当前用户进程+线程总数限制,cat /proc/sys/kernel/threads-max看内核总线程上限;三者取最小值即实际瓶颈,任一未调大均会导致fork失败或Java报unable to create new native thread。

改 kernel.pid_max 只是第一步,不配 ulimit -u 和 kernel.threads-max,照样 fork 失败。
怎么确认当前系统卡在哪个限制上
别猜,直接查三处:
-
cat /proc/sys/kernel/pid_max—— 看全局 PID 池上限(x86_64 最高 4194304) -
ulimit -u—— 看当前用户能占多少个 PID(含进程+线程),普通用户常被设成 1024 或 4096 -
cat /proc/sys/kernel/threads-max—— 看内核实际允许的总线程数,它 ≈ 内存页数 / 8,且不能超过pid_max
错误现象通常是 fork: Cannot allocate memory 或 Java 报 java.lang.OutOfMemoryError: unable to create new native thread,但 dmesg | tail 会显示 PID allocation failure,这才是真凶。
临时修改 kernel.pid_max 的实操要点
适合验证或应急,重启即失效:
- 必须用
sudo:执行sudo sysctl -w kernel.pid_max=196608 - 别写进
/proc/sys/文件时漏掉sudo,否则 Permission denied - 设太高会被静默截断:x86_64 上设成 8388608,内核只认 4194304
- 改完立刻生效,但当前 shell 的
ps不会变多——它影响的是后续fork()调用
为什么改了 pid_max 还是创建不了线程
因为真正拦住你的,是三个值里的最小值:
-
pid_max是全局池子大小 -
threads-max是内核能支撑的总线程上限(受内存限制) -
ulimit -u是用户级硬闸,systemd 服务默认完全忽略/etc/security/limits.conf
例如:pid_max=4194304,threads-max=139264,但 ulimit -u=4096,那 Java 应用开到第 4097 个线程就挂——pid_max 再大也没用。systemd 服务还得单独加 LimitNPROC=65535 到 .service 文件里。
永久生效要绕过几个配置陷阱
别只往 /etc/sysctl.conf 里硬塞:
- 优先用
/etc/sysctl.d/99-pidmax.conf,避免和发行版默认配置冲突 - 写完必须运行
sudo sysctl --system(不是sysctl -p),否则.d/目录下的文件不加载 - RHEL/CentOS 7+ 可能需要
sudo systemctl restart systemd-sysctl - 检查等号前后有没有空格、行尾有没有不可见字符——
sysctl解析极严格,错一个字符就静默失败
改完一定再跑一遍 cat /proc/sys/kernel/pid_max,看到你写的值才算真生效。别信“我改过了”,Linux 不会主动告诉你配错了。











