ulimit -n当前 Shell(及其子进程)能打开的最大文件描述符数。
约 1283 字大约 4 分钟
2026-05-14
Too many open files 是一个让新手摸不着头脑的报错——磁盘没满、内存没爆,怎么就“文件太多”了?关键在于:这里的“文件”不只是磁盘文件,还包括网络连接;而每个进程能同时打开多少,是有上限的。这篇讲清文件描述符和 ulimit。
理解文件描述符(fd)涵盖文件和 socket,进程有打开数上限,掌握 ulimit 查看限制、为 systemd 服务正确设置 LimitNOFILE。
ulimit -n当前 Shell(及其子进程)能打开的最大文件描述符数。
ls /proc/PID/fd | wc -l数一个进程当前实际打开了多少个 fd。
lsof -p PID列出某进程打开的全部 fd——文件、socket、管道都在内。
systemctl show 服务 -p LimitNOFILEsystemd 服务的 fd 上限由 unit 决定,不是登录 Shell 的 ulimit。
进程每打开一样东西,内核就给它一个编号,叫文件描述符(fd)。关键点是——这个“东西”范围很广:
所以一个高并发的网络服务,可能磁盘文件没开几个,但因为有上万个并发连接,fd 数飙得很高。这就是为什么 Too many open files 经常出现在网络服务上。
fd 数量有两道天花板:
| 层级 | 限制谁 | 怎么看 |
|---|---|---|
| 进程级(ulimit) | 单个进程能开多少 | ulimit -n |
| 系统级 | 整个系统所有进程加起来 | cat /proc/sys/fs/file-nr |
绝大多数 Too many open files 撞的是进程级的 ulimit -n——默认值可能只有 1024,对一个高并发服务远远不够。
固定路线:
# 1. 找到出问题的进程 PID,看它开了多少 fd
ls /proc/PID/fd | wc -l
# 2. 看这个进程的上限是多少
cat /proc/PID/limits | grep "open files"
# 3. 看它都开了些什么——是文件泄漏,还是正常的大量连接
lsof -p PID两种结论:① fd 数接近上限、且大多是正常连接 → 上限设小了,该调大;② fd 一直涨、有大量本该关闭的文件没关 → 是程序的 fd 泄漏 bug,调大上限只是拖延,得修代码。
一个超高频的坑:你 ulimit -n 改大了,服务还是报 Too many open files。
因为 systemd 管理的服务,根本不读你登录 Shell 的 ulimit(原理同 Shell 是什么 里讲的非交互环境)。服务的 fd 上限由它的 unit 文件决定:
[Service]
LimitNOFILE=65536改 unit 文件后要 systemctl daemon-reload 再重启服务(见 systemd 基础)。在终端里 ulimit -n 对 systemd 服务完全无效——这一点不知道,能排查到怀疑人生。
调大 ulimit 前先判断是不是 fd 泄漏
Too many open files 最省事的“修复”是把 ulimit 调大,但这经常是治标不治本。如果根因是程序打开文件 / 连接后没关闭(fd 泄漏),调大上限只是把崩溃推迟几小时——ls /proc/PID/fd | wc -l 持续往上涨、不回落,就是泄漏的信号。先用 lsof -p 看它开的到底是不是正常该有的东西,确认是“正常的高并发”再调上限,确认是泄漏就去修程序。
| 误区 | 更稳妥的做法 |
|---|---|
| 以为 fd 只是磁盘文件 | socket、网络连接都占 fd,高并发服务 fd 主要是连接 |
改了登录 Shell 的 ulimit -n 期望服务生效 | systemd 服务看 unit 里的 LimitNOFILE,不看登录 Shell |
| 一报 Too many open files 就调大上限 | 先判断是正常高并发还是 fd 泄漏,泄漏要修程序 |
| 只看进程级限制 | 系统级 /proc/sys/fs/file-nr 也有天花板,别漏 |
版权归属:Shuo Liu