ulimit -u 限制用户进程与线程总数而非仅线程,真正瓶颈常在此;需同步调优 ulimit -u、systemd LimitNPROC、/proc/sys/kernel/threads-max 和 pid_max 四层限制,并用 ps -eLf | wc -l 与 prlimit -n 验证生效。

ulimit -u 是最常被误读的“线程数限制”
它不是线程专用限制,而是“每个用户能拥有的进程+线程总数”,Linux 内核把线程当作轻量进程(LWP)处理,ulimit -u 一并约束两者。你看到 unable to create new native thread,90% 情况下卡在这里,而不是 Java 堆或 GC 问题。
查当前值:ulimit -u;查进程/线程实际占用:ps -eLf | wc -l;对比 /proc/sys/kernel/threads-max —— 如果二者接近,说明真触顶了。
- 临时改:当前 shell 生效,
ulimit -u 65535 - 永久改:必须写进
/etc/security/limits.d/20-nproc.conf(CentOS 7 默认生效文件),不是/etc/security/limits.conf—— 后者会被20-nproc.conf覆盖 - 内容格式必须是:
* soft nproc 65535和* hard nproc 65535,不能写成noproc或漏掉hard - root 用户也要单独配,否则 SSH 登录后仍继承默认 4096;普通用户改完需重新登录(不是
source或重启终端)
systemd 服务不认 limits.conf,得单独喂 LimitNPROC
用 systemctl start myapp.service 启的服务,完全无视 /etc/security/limits.d/ 下的配置。它走的是 systemd 的资源控制路径,ulimit -u 对它无效。
CentOS Linux 7.9.2009是传统CentOS Linux 7的最后主要版本,也是很多企业历史服务器中仍可能遇到的系统版本。它以稳定、兼容RHEL 7生态、文档丰富和软件支持广泛著称,曾长期用于Web服务、数据库、虚拟化节点和企业内部业务系统。不过CentOS Linux 7已于2024年6月30日停止维护,现在继续使用会面临安全补丁缺失风险。该版本更适合旧业务迁移、历史环境恢复或离
- 编辑 service 文件:
/etc/systemd/system/myapp.service - 在
[Service]段加:LimitNPROC=65535 - 或者全局设:
DefaultLimitNPROC=65535写入/etc/systemd/system.conf,再执行sudo systemctl daemon-reload - 验证是否生效:
systemctl show myapp.service | grep NPROC,或查运行中进程的限制:prlimit -n $(pgrep -f myapp)
/proc/sys/kernel/threads-max 才是真正的系统级硬闸
即使 ulimit -u 和 LimitNPROC 都调高了,ps -eLf | wc -l 还卡在几万,就该看这个值。它是内核允许创建的总线程数上限,由内存和 pid_max 共同决定。
- 查当前值:
cat /proc/sys/kernel/threads-max - 临时调高:
sudo sysctl -w kernel.threads-max=2097152 - 但必须先确认:
cat /proc/sys/kernel/pid_max≥ 你想设的threads-max值,否则报Invalid argument - 永久生效:写
kernel.threads-max = 2097152到/etc/sysctl.d/99-thread-limit.conf,再运行sudo sysctl --system - RHEL/CentOS 7+ 还要
sudo systemctl restart systemd-sysctl
别忘了 pid_max —— 线程没死,只是拿不到 PID
当 ulimit -u、threads-max 都放开,却突然出现 fork: Cannot allocate memory,八成是 pid_max 耗尽。PID 是所有进程/线程的唯一标识,池子空了,新建线程就卡在分配阶段。
- 查当前值:
cat /proc/sys/kernel/pid_max - 临时调:
sudo sysctl -w kernel.pid_max=4194304 - 永久配置:写
kernel.pid_max = 4194304到/etc/sysctl.d/99-pid-limit.conf,再sudo sysctl --system - 注意:容器环境(如 Docker/K8s)里,
pid_max是 namespace 级别的,宿主机设置不影响容器,得靠--pid=host或 K8s 的securityContext.procMount控制
真正卡住线程创建的,往往不是单一配置,而是三层叠加:用户级(ulimit -u)、服务级(LimitNPROC)、内核级(threads-max 和 pid_max)。改一个不等于全通,必须逐层验证,尤其别忽略 ps -eLf | wc -l 和 prlimit -n $PID 这两个实测命令。

















