直接看/proc/$pid/limits最准确,它反映内核对该进程实际生效的软硬限制,如Max open files为1024 1024而程序尝试打开第1025个文件就会因EMFILE失败或阻塞。

怎么看进程是不是被资源限制卡住
直接看 /proc/$pid/limits 是最准的——它不看你登录时 ulimit 设了多少,也不管 limits.conf 有没有生效,只反映这个进程此刻内核实际 enforce 的软硬限制。比如 Max open files 行显示 1024 1024,而你的程序正试图打开第 1025 个文件,那它就会在 open() 或 socket() 上阻塞或失败,不是挂起就是报 EMFILE。
- 先确认 PID:用
ps aux | grep myapp或pgrep -f "myapp" - 再查限制:
cat /proc/1234/limits | grep "open files"(把 1234 换成真实 PID) - 如果输出是
unlimited,但程序还是卡,说明问题不在文件描述符,得查别的资源,比如Max processes或 cgroup 限制 - 注意:普通用户只能看自己进程的
/proc/$pid/limits,看别人会 Permission denied
挂起时怎么判断是资源限制导致的
资源限制导致的“挂起”通常不是真死锁,而是系统调用被阻塞或返回错误。常见现象包括:
- 进程状态为
D(不可中断睡眠)或R+(运行中但卡在系统调用),用ps -o pid,comm,wchan,state -p 1234看 -
strace -p 1234显示卡在openat(...)、socket(...)、fork()等调用上,且返回-1 EMFILE或-1 EAGAIN -
lsof -p 1234 | wc -l数出当前打开的 fd 数,接近或等于/proc/1234/limits里软限制值 - 日志里出现 “Too many open files”、“Resource temporarily unavailable”、“Cannot allocate memory” 等字样
prlimit 能不能救活已挂起的进程
能,但有严格前提:必须是 root,且目标进程还没因资源耗尽彻底崩溃。
- 对已运行的进程提软限制:
prlimit -p 1234 --nofile=4096:4096(软硬一起设) - 普通用户只能降自己的软限制,或把软限制提到当前硬限制范围内;要提硬限制,必须 root
- systemd 启动的服务可能被
LimitNOFILE=覆盖,改完立刻被拉回,得先改 service 文件再 reload - 子进程不会自动继承父进程被 prlimit 修改后的限制,除非 exec 新程序
-
/proc/$pid/limits是只读虚拟文件,echo ... > /proc/1234/limits必定失败,别试
为什么改了 limits.conf 还是没用
因为 /etc/security/limits.conf 只在用户登录会话建立时由 pam_limits.so 加载一次,对已运行进程、非 login shell 启动的进程(如 cron、systemd、docker)完全无效。
- systemd 服务必须显式配置
LimitNOFILE=在 unit 文件里,或全局设DefaultLimitNOFILE= - docker 容器需用
--ulimit nofile=65536:65536启动,镜像里改 limits.conf 没用 - 脚本里用
ulimit -n 65536只影响当前 shell 和后续 fork 出的子进程,不影响已存在的 PID - 检查是否生效,唯一可靠方式是
cat /proc/$pid/limits,不是看 ulimit -n 当前 shell 的值
真正麻烦的是那些被 cgroup 或 systemd 隐式限制的场景——/proc/$pid/limits 显示 unlimited,但实际被掐在更底层。这时候得查 systemctl show myapp.service | grep LimitNOFILE 或 cat /sys/fs/cgroup/pids/myapp/pids.max,否则容易漏掉关键约束。


















