当前系统线程数限制由/proc/sys/kernel/threads-max决定,其值受物理内存和pid_max约束;临时修改需root权限且pid_max≥threads-max,永久配置应写入/etc/sysctl.d/并执行sysctl --system。

查看当前系统线程数限制
线程本质是轻量级进程,受 /proc/sys/kernel/threads-max 和 /proc/sys/kernel/pid_max 共同约束,但真正卡住你新建线程的,通常是前者。别只看 ulimit -u(那是用户级进程+线程总数),它不反映内核能支撑的上限。
执行以下命令确认现状:
cat /proc/sys/kernel/threads-max<br>cat /proc/sys/kernel/pid_max
常见现象:Java 应用报 java.lang.OutOfMemoryError: unable to create new native thread,而堆内存充足——大概率就是 threads-max 到顶了。
-
threads-max默认值 ≈mem_total_kb / (4 * page_size),物理内存越大,初始值越高,但不是无限涨 -
pid_max必须 ≥threads-max,否则内核会静默截断;改threads-max前先检查这个 - 该值是全局的,所有用户、所有进程共享,不是 per-user 或 per-cgroup
临时修改 threads-max(重启失效)
直接写入 /proc 是最快速验证方式,适合调试或临时扩容:
echo 65536 > /proc/sys/kernel/threads-max
注意权限和依赖:
- 必须用 root 执行,普通用户写会报
Permission denied - 如果
pid_max小于新设值,写入会失败,错误提示是Invalid argument - 该操作即时生效,无需 reload 任何服务,已运行的线程不受影响
- 容器内修改仅对当前容器 namespace 生效(若未禁用 procfs 挂载)
永久生效:通过 sysctl 配置
把配置固化到 /etc/sysctl.conf 或 /etc/sysctl.d/*.conf,避免重启后回退:
echo "kernel.threads-max = 65536" >> /etc/sysctl.d/99-thread-limit.conf<br>sysctl --system
关键细节:
- 不要直接改
/etc/sysctl.conf主文件,优先用/etc/sysctl.d/下的独立文件,便于管理与卸载 -
sysctl --system会重载全部配置,比单独sysctl -p更可靠(后者可能漏掉.d目录) - 某些发行版(如 RHEL/CentOS 7+)默认启用
systemd-sysctl,配置文件修改后需systemctl restart systemd-sysctl才生效 - 值不能超过
pid_max,建议同步检查并按需调整:sysctl kernel.pid_max
为什么改了还是创建失败?排查路径
线程创建失败不全是 threads-max 的锅,尤其在容器或高并发服务中,常被忽略的还有:
-
ulimit -u(即RLIMIT_NPROC)限制单个用户可拥有的进程/线程总数,Java 进程启动时继承 shell 限制,ps -eLf | grep java | wc -l可查实际线程数 - 内存不足:每个线程栈默认 8MB(x86_64),1000 个线程就占 8GB 虚拟内存,
ENOMEM错误可能是vm.overcommit_memory=2下真实内存不够 - 容器场景:Docker/K8s 默认限制
pids.limit,需显式配置--pids-limit或resources.pids,宿主机的threads-max对容器无直接作用 - glibc 版本较老时,
pthread_create在fork()失败后也可能返回类似错误,需结合dmesg | tail看是否出现Out of memory: Kill process
调优不是改一个数字就完事,threads-max 是底座,但上层应用的资源视图、cgroup 边界、内存分配策略,都得串起来看。








