/etc/security/limits.conf 仅对经pam登录的交互式会话生效,systemd服务、cron、非交互ssh等不加载它;验证需新终端su登录后用ulimit -n或直接查/proc/$pid/limits;systemd服务限制由unit文件或defaultlimitnofile控制,与limits.conf无关。

怎么确认 /etc/security/limits.conf 是否被加载
直接 cat /etc/security/limits.conf 只能看到配置内容,不代表它已生效。PAM 模块必须在登录会话建立时读取该文件,而 systemd 服务、cron 任务、SSH 非交互式登录(如 ssh user@host command)通常不触发 PAM limits 加载。
- 检查当前 shell 是否走 PAM:运行
loginctl show-user $USER | grep -q "Linger" && echo "PAM likely active";更可靠的是看ps -o comm= -p $PPID是否为login或sshd - 验证配置是否解析成功:临时加一行
* soft nofile 99999到/etc/security/limits.conf,然后用新终端su - $USER登录,再执行ulimit -n—— 若输出是99999,说明加载成功 - 注意
/etc/security/limits.d/*.conf里的文件会按字母序合并覆盖,90-nofile.conf会覆盖10-default.conf中同项设置
为什么 cat /proc/$pid/limits 比 ulimit -a 更准
ulimit -a 显示的是当前 shell 进程的软限制快照,而 /proc/$pid/limits 是内核为**那个具体进程**维护的实时状态,不受 shell 环境变更或子进程继承偏差干扰。
- 对 systemd 服务:即使你改了
ulimit -n,systemctl start myapp启动的进程仍按 unit 文件或 DefaultLimitNOFILE 设置,cat /proc/$(pgrep myapp)/limits | grep "open files"才是真相 - 对容器内进程:
docker run --ulimit nofile=65536:65536启动后,进容器查/proc/1/limits才能确认是否真落到 PID 1 上 - 若输出某行显示
unlimited,别急着认为没限制——先查systemctl show myapp.service | grep LimitNOFILE,cgroup v2 下硬限制可能被memory.max或pids.max间接卡住
systemd 服务的资源限制文件在哪
systemd 不读 /etc/security/limits.conf,它的限制由 unit 文件和全局默认值控制,优先级:service unit > /etc/systemd/system.conf.d/*.conf > /etc/systemd/system.conf > /usr/lib/systemd/system.conf。
- 查服务自身设置:
systemctl cat myapp.service | grep -E "(Limit|NOFILE)",关注LimitNOFILE=、LimitNPROC=等字段 - 查全局默认:
systemctl show --property=DefaultLimitNOFILE,这个值会作为所有未显式声明 Limit 的服务的 fallback - 修改后必须
systemctl daemon-reload,且已有服务需systemctl restart myapp才会重新应用限制——仅 reload 不影响正在运行的进程
哪些“配置文件”其实根本不控制进程限制
常见误判点:以为改了某些路径就等于改了运行中进程的限制,实际它们要么只影响启动上下文,要么压根不参与资源配额决策。
-
/proc/sys/fs/file-max控制的是**全系统**最大句柄数,不是单进程限制,改它不会让某个进程 suddenly 能开更多 fd -
/etc/sysctl.conf里的fs.file-max是持久化/proc/sys/fs/file-max的方式,同样不作用于进程级 -
/proc/$pid/limits是只读虚拟文件,echo "xxx" > /proc/1234/limits必报Invalid argument或Permission denied—— 内核禁止写入,这不是 bug,是设计 - bash 的
~/.bashrc里写ulimit -n 65536,只对新打开的交互式 bash 生效,对systemd、crond、dockerd启动的进程完全无效
真正要定位一个进程的限制来源,得顺着它的启动链往回推:是 login shell?systemd unit?container runtime?还是直接 fork 自 init?每种路径对应不同的配置入口,漏掉任一环都可能白调。











