可用ls /proc/[pid]/fd | wc -w直接统计进程fd总数,该方法轻量、可靠、不依赖外部命令;注意需过滤.和..,推荐用ls /proc/[pid]/fd | grep -e '^[0-9]+$' | wc -l精确计数纯数字fd。

怎么用 ls /proc/[PID]/fd 快速统计每个进程的 fd 数量
直接数 /proc/[PID]/fd 目录里的链接数,是最轻量、最可靠的方式——不依赖外部命令,也不受权限限制(只要能读该目录)。ls /proc/[PID]/fd | wc -w 输出的就是当前进程打开的 fd 总数。
常见错误:直接 ls /proc/[PID]/fd 不加管道,容易忽略隐藏文件(比如 . 和 ..),导致多算 2 个;正确做法是用 ls | wc -w 或 ls -A | wc -w 配合过滤。
- 只统计纯数字 fd(排除
...):ls /proc/[PID]/fd | grep -E '^[0-9]+$' | wc -l - 批量查多个进程(如所有 nginx 进程):
ps -eo pid,comm | awk '/nginx/{print $1}' | xargs -I{} sh -c 'echo "{}: $(ls /proc/{}/fd 2>/dev/null | grep -E "^[0-9]+$" | wc -l)"' - 注意:
ls /proc/[PID]/fd对已退出但未完全清理的僵尸进程会失败(No such file or directory),需提前ps确认进程状态
lsof -p [PID] 能看到什么,为什么不能直接排序
lsof -p [PID] 输出的是每条 fd 的详细信息(类型、设备、节点、访问模式、路径等),但它本身不提供“按 fd 编号排序”或“按数量聚合”的能力。你得靠后续工具处理。
真正有用的组合是:lsof -p [PID] | awk ' ~ /^[0-9]+$/ {print }' | sort -n | uniq -c | sort -nr —— 这才给出该进程内各 fd 编号的出现频次(通常为 1,但某些异常情况如 dup/dup2 可能重复)。
- 别信
lsof -p [PID] | wc -l:它包含表头行,实际 fd 数要减 1 -
lsof默认只显示用户有权限查看的 fd;root 下才看到全部(比如 socket、eventpoll) - 某些 fd 指向
anon_inode:[eventpoll]或socket:[123456],无法直接对应到磁盘路径,但仍是有效占用
想看全系统 fd 占用排名,cat /proc/sys/fs/file-nr 和 ulimit -n 是关键指标
单个进程的 fd 排名意义有限,真正压垮系统的往往是全局 fd 耗尽。这时要看三个值:cat /proc/sys/fs/file-nr 输出的三元组(已分配 / 已分配未用 / 系统上限),以及各进程的 ulimit -n 设置。
例如输出 12345 678 98765,说明当前已用 12345 个 fd,离系统上限还有很大余量;但如果某个进程 ulimit -n 是 1024,而它已经打开 1023 个文件,就极可能触发 “Too many open files” 错误。
- 查所有进程的 ulimit:
for pid in /proc/[0-9]*; do echo "$(basename $pid): $(cat $pid/limits 2>/dev/null | awk '/Max open files/{print $4}')"; done | sort -k2,2nr | head -10 - 查哪些进程接近自己的 ulimit 上限:
for pid in /proc/[0-9]*; do n=$(ls "$pid/fd" 2>/dev/null | grep -E '^[0-9]+$' | wc -l 2>/dev/null); lim=$(cat "$pid/limits" 2>/dev/null | awk '/Max open files/{print $4}'); [ "$n" -gt "$((lim * 9 / 10))" ] && echo "$pid: $n/$lim"; done -
/proc/sys/fs/file-max是硬上限,改它需要 root 权限和 sysctl 配置;临时调高可用echo 200000 > /proc/sys/fs/file-max
为什么 du 和 find 查不到 fd 占用?别混淆概念
文件描述符不是“文件大小”,而是内核中一个整数索引,指向打开的文件、socket、管道、设备等资源。所以 du -sh /proc/*/fd 永远显示 0,find /proc -name fd -type d 也查不到“占用空间”——它根本不占磁盘空间。
真正要定位 fd 泄漏,得结合行为特征:比如某服务重启后 fd 数持续上涨、日志里频繁出现 EMFILE 错误、strace -p [PID] -e trace=open,openat,close 观察系统调用失衡。
- 不要试图用
ncdu /proc/[PID]/fd—— 它对符号链接无效,且会报权限错误 -
lsof +D /proc是危险操作,会尝试遍历所有进程 fd 目录,极易卡死终端 - 最实用的现场快照:
ls -l /proc/[PID]/fd 2>/dev/null | head -20,一眼看出是否有大量socket:或pipe:堆积











