需同步调高 ulimit -u 和 /proc/sys/kernel/pid_max,并配合构建工具并发控制,才能有效防止自动化构建因 fork 爆炸或线程耗尽导致卡死;linux 中线程也占用 pid,ulimit -u 限制的是用户级进程与线程总数,默认值过低易触发 fork 失败、unable to create new native thread 等错误。

直接调高 ulimit -u(用户进程/线程总数)和 /proc/sys/kernel/pid_max(系统 PID 上限),再配合构建工具本身的并发控制,就能有效防止自动化构建因 fork 爆炸或线程耗尽导致卡死甚至假死。
重点不是“只加线程数”,而是两层限制必须同步放开
自动化构建(如 Jenkins、GitLab CI runner、Make -j、CMake Ninja)常启动大量子进程和线程:编译器进程、链接器、预处理器、并行任务调度器等。Linux 中线程也占 PID,ulimit -u 限制的是该用户所有进程 + 线程总和——不是“纯进程数”。默认值往往只有 500~4096,大项目开 -j16 就可能突破。
-
现象典型表现:构建中途卡住、
fork: Resource temporarily unavailable、Java 报unable to create new native thread、ps -eLf | wc -l接近ulimit -u值 -
关键误区:只改
ulimit -u却没调/proc/sys/kernel/pid_max,会导致“用户允许开 65535,内核却只剩 32768 个 PID 可分”,照样失败 -
验证方式:在构建用户下运行
ulimit -u和cat /proc/sys/kernel/pid_max;进正在跑的构建进程查真实限制:prlimit -n $PID | grep "MAX PROCESSES"
永久生效配置(避免每次手动 ulimit)
临时加 ulimit -u 65535 && make -j16 只适合调试。生产级 CI 构建需固化配置:
- 编辑
/etc/security/limits.conf,添加(注意用 tab 或空格分隔,不能混用):
* soft nproc 65535
* hard nproc 65535
* soft nofile 409600
* hard nofile 409600 - 确认 PAM 加载生效:检查
/etc/pam.d/common-session是否含session required pam_limits.so - 若构建由 systemd 服务托管(如
gitlab-runner.service),必须额外声明:
在[Service]段加LimitNPROC=65535,再执行systemctl daemon-reload && systemctl restart gitlab-runner
内核级兜底:调高 pid_max 防止全局耗尽
pid_max 是内核能分配的 PID 总数上限,默认 x86_64 是 32768,高并发构建极易打满。不改它,前面所有 ulimit 设置都可能失效。
- 查看当前值:
cat /proc/sys/kernel/pid_max - 临时生效:
sudo sysctl -w kernel.pid_max=4194304 - 永久生效:在
/etc/sysctl.conf追加kernel.pid_max = 4194304,再运行sudo sysctl -p
构建工具层主动降压(比硬扛更稳妥)
资源上限调高是必要基础,但合理控制并发才是防死机的关键。不要盲目 make -j$(nproc):
- 对 GCC/Clang 编译:用
make -j$(($(nproc)/2 + 1))留出内存余量,避免 OOM killer 杀进程 - 对 Maven/Gradle:设
-Dmaven.parallel.threads=2C或--max-workers=4,避免 JVM 线程爆炸 - CI 脚本开头显式声明:
ulimit -Sv 8388608(限制虚拟内存 8GB),防单个编译单元吃光内存 - 监控辅助:在构建前加
echo "PIDs used: $(ps -U $USER --no-headers | wc -l)",超阈值时自动降级并发数











