为什么总提示“打开文件过多”,还伴随僵尸进程?

用 ss 和 lsof 找出泄漏文件描述符的进程,再用 ulimit 提高上限,并让配置在重新登录后依然生效。

Linux进程网络磁盘端口故障排查netstat 连接状态中风险
先别急着调大上限,先用 ss 查清哪个进程占着最多连接,再用 lsof 确认是不是真的在泄漏描述符。

快速开始

“Too many open files” 和僵尸进程往往同时出现,因为根源常常是同一个不听话的服务:它只打开文件描述符却不关闭,只创建子进程却不回收。也正因为如此,单纯把上限调高只能拖延故障。本指南从定位作乱进程开始,接着调高上限,最后把配置固化下来,让它在下次登录或重启后依然有效。

症状

?日志和终端里不断刷出 “Too many open files”;新连接被拒绝、老连接卡住不动;原本正常的定时任务和脚本开始报错。与此同时,进程列表里能看到状态为 Z 的子进程,数量只增不减,因为父进程从不读取它们的退出状态。而此时 CPU 和内存看起来都很正常,这正是它让人摸不着头脑的地方。

先看清是哪个进程占着大量 socket

不要凭感觉调参数,先数一数。这个视图会把所有监听中和已建立的 TCP/UDP 连接连同所属进程一起列出来,如果某个服务挂着几百条连接,一眼就能看出来。这种形态通常说明是单个程序在泄漏文件描述符,而不是整台机器的上限不够用。这一步做完,你应该能说出占用最多的那个进程名字,并记下它的 PID。

查看哪些服务在监听哪些端口、谁在连接——现代版的 netstat。

命令
$ sudo ss -tulpn

用“已删除但仍被打开的文件”确认泄漏

如果程序打开文件、删除它,却从不关闭,这个描述符就会一直存在 — 这类文件在列表里的链接数为 0。若同一个 PID 反复出现,说明问题确实是泄漏,而不是上限设得太小,此时单纯调高上限只会把崩溃时间往后推。查看别人的描述符需要 root 权限,所以会提示输入密码,这是正常的。

当 df 显示磁盘满但 du 却找不到大文件时,多半是有进程还握着已删除的文件;lsof +L1 能把它们和占用进程一起列出来。

命令
$ sudo lsof +L1

在启动服务的那个 shell 里调高描述符上限

进程的上限是从 fork 它的 shell 继承来的,所以必须在服务启动之前、在同一个 shell 里修改。用那个既能查看又能设置上限的 shell 内置命令,把数值调大,之后从该 shell 启动的程序就不会再立刻报“打开文件过多”。设置完在同一个会话里再打印一次确认,数值变大了就说明生效;退出登录后这个改动会丢失。

ulimit -n 可查看或修改当前 shell 的文件描述符上限,解决从该 shell 启动的服务报“Too many open files”的问题。

命令
$ ulimit -n 4096
▾ 撤销
撤销
$ ulimit -n 1024

让新上限在重新登录后依然有效

刚设置的数值只活在当前 shell 里。就地编辑 PAM 的 limits 配置文件,可以让每个新登录会话都拿到更高的上限,服务器上一般都需要这样做。由于就地编辑会直接写盘,先留一份备份,免得写错语法之后连自己都登不进去。验证方式是另开一个全新会话,在里面打印上限,看到的数字应该是调大后的值;另外别忘了,已经在跑的服务必须重启才会继承新上限。

Linuxsed -i:命令行直接原地编辑文件中风险步骤 4可选

用 sed -i 在 Linux 上对单个或多个文件做查找替换,配合 -i.bak 保留备份。

命令
$ sed -i 's/old-domain.com/new-domain.com/g' *.conf
▾ 撤销
撤销
$ git checkout -- *.conf  (or restore from the .bak created by sed -i.bak)
!上限不是越高越好 — 每个描述符都要占用内核内存,而且上面还有系统级的上限在约束。就地编辑 PAM 的 limits 配置文件是直接写盘的,动手前先备份,并另留一个 root 会话;写错语法可能导致你再也登录不进去。也别用“定时重启服务”来掩盖泄漏,那只是把问题藏起来。

如何确认已解决

改动之后再跑一次 socket 列表,盯住那个作乱进程:连接数停在新上限之下且不再持续上涨。新开的登录会话显示的是调大后的数值,日志里不再出现新报错,父进程重启后僵尸条目也随之消失。

一键全部撤销

上面每一条命令都可以撤销。按此顺序执行即可全部还原。

一键全部撤销
$ git checkout -- *.conf  (or restore from the .bak created by sed -i.bak)
ulimit -n 1024

执行前请先确认——部分步骤之间可能并非相互独立。

来源

  • lsof(8) - Linux manual page
    Ubuntu Manpages · technical · 2026-09-17
    依据: The +L1 option selects files with a link count less than one, i.e. open files that have been unlinked (deleted).
  • Sed — ArchWiki
    Arch Linux · community · 2026-09-17
    依据: Examples of GNU sed -i in-place editing and -i.bak backup extension usage
  • getrlimit(2)/setrlimit(2) - get/set resource limits
    man7.org Linux man-pages · technical · 2026-09-17
    依据: RLIMIT_NOFILE specifies a value one greater than the maximum file descriptor number that can be opened by this process; limits have a soft value (enforced) and a hard value (ceiling for the soft).
  • ss(8) — Arch Manual Pages
    Arch Linux · community · 2026-09-17
    依据: Same options documented for ss, another utility to investigate sockets.
  • ss(8) — Debian bookworm
    Debian Manpages · community · 2026-09-17
    依据: Documents -t/--tcp, -u/--udp, -l/--listening, -p/--processes and -n/--numeric for the socket statistics tool.
  • sed(1P) — POSIX manual page
    man7.org · technical · 2026-09-17
    依据: Documents the s/re/replacement/flags substitution, /g global flag, and address ranges

最后验证: 2026-09-22

相关指南