最准方法是统计 /proc/[pid]/fd/ 目录下符号链接数;单进程上限看 ulimit -Sn/-Hn,系统上限看 /proc/sys/fs/file-max;lsof -i 仅统计网络 socket,漏掉大量非网络句柄。

怎么查当前进程打开的文件句柄数
直接看 /proc/[pid]/fd/ 目录里的链接数量,最准。Linux 里“打开文件”基本等价于“打开句柄”,每个句柄在该目录下对应一个符号链接。
- 查自己 shell 进程:
ls -l /proc/$$/fd/ | wc -l - 查某个具体进程(比如 nginx 主进程):
ls -l /proc/$(pgrep nginx | head -n1)/fd/ 2>/dev/null | wc -l - 注意:
2>/dev/null是为了屏蔽权限拒绝(如其他用户进程),否则会干扰计数
系统级句柄上限在哪看
有两个关键限制:单进程上限(RLIMIT_NOFILE)和全系统上限(fs.file-max)。别只盯一个。
- 查当前 shell 的单进程软硬限制:
ulimit -Sn(软限)、ulimit -Hn(硬限) - 查内核级总上限:
cat /proc/sys/fs/file-max - 查当前已分配句柄总数(近似值):
cat /proc/sys/fs/file-nr—— 输出三列,第三列才是系统级最大值,第二列是已用数
为什么 lsof -i 统计不准
lsof -i 只列网络 socket,漏掉普通文件、管道、设备、eventfd、timerfd 等大量非网络句柄。它不是“查打开文件”的正确姿势。
- 真正想看某进程所有句柄:
lsof -p [pid]或直接ls /proc/[pid]/fd/ -
lsof | wc -l容易因权限失败中断,且输出含表头和空行,计数不可靠 - 高并发服务(如 Redis、Node.js)常创建大量非 socket 句柄,只跑
lsof -i会严重低估真实压力
改句柄上限容易踩的坑
改了配置不生效?大概率是没分清作用域或没触发重载。
- 临时调高单进程上限:
ulimit -n 65536,但只对当前 shell 及其子进程有效 - 永久修改需写入
/etc/security/limits.conf,格式必须是:username soft nofile 65536+username hard nofile 65536,且用户需重新登录才生效 - 改系统级
fs.file-max:sysctl -w fs.file-max=2097152,要持久化得写进/etc/sysctl.conf - systemd 服务绕过 limits.conf:必须在 service 文件里加
LimitNOFILE=65536,否则 ulimit 设置无效
句柄耗尽往往发生在连接密集但连接生命周期短的场景(比如 HTTP 短连接暴增),这时候看 file-nr 第二列比盯着某个进程更早发现问题。别等 Too many open files 报错才查。










