You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux进程文件描述符计数差异:lsof与/proc/fd结果不一致排查

为什么三种方式统计MongoDB进程的文件描述符数量差异这么大?

这问题我之前排查FD泄漏时也遇到过,咱们一步步拆解为什么三个结果差这么大,哪个才是和你遇到的too many open files错误直接相关的答案:

1. 哪个结果是正确的?

  • ll /proc/20341/fd | wc -l得到的499,是当前MongoDB进程实际持有的打开文件描述符(FD)数量,这个数值是操作系统层面的真实计数,和你遇到的too many open files错误直接相关。
  • lsof -p 20341 | wc -l的570是包含了更多非FD的文件对象,有一定参考性但不是真实FD数。
  • lsof | grep 20341 | wc -l的282223完全是重复统计的结果,没有参考价值。

2. 三种方式的差异原因

(1)/proc/<pid>/fd的计数逻辑

/proc/<pid>/fd是Linux内核暴露的进程文件描述符目录,里面的每个符号链接都对应进程当前正在使用的文件描述符——不管是普通文件、套接字还是管道,只要占用了一个FD,就会在这里有一个对应的链接。这个目录的条目数就是进程实际占用的FD数量,是排查FD泄漏最准确的指标。

(2)lsof -p <pid>的计数逻辑

lsof会列出进程关联的所有文件对象,而不仅仅是占用FD的文件:

  • 它会包含进程的当前工作目录(cwd)、根目录(rtd)、可执行文件本身(txt);
  • 还会包含通过mmap映射到内存的文件(比如你输出里的mem类型条目,MongoDB会把数据文件映射到内存加速访问,这些映射不占用文件描述符);
  • 再加上真正的FD条目(比如输出里的490u、491u这类带数字和权限标识的条目),所以总数会比/proc/<pid>/fd多。

如果想通过lsof得到真实FD数,可以过滤出FD列是数字加权限的条目:

lsof -p 20341 | grep -E '^(COMMAND|.*[0-9]+[urw])' | wc -l

这个结果会和/proc/<pid>/fd的计数更接近。

(3)lsof | grep <pid>的计数逻辑

这个命令的问题最大,因为:

  • lsof默认会显示进程的所有线程(你输出里的27018、32608就是MongoDB的线程ID);
  • 同一个文件描述符会被每个线程重复统计!比如你输出里的492u这个TCP连接,在27018和32608两个线程里都被列出来了,导致同一个FD被多次计数,最终总数暴增到28万+,完全是重复统计的虚高数值,不能用来判断FD占用情况。

3. 回到你的初始问题

你一开始用lsof -n |awk '{print $2}'|sort|uniq -c |sort -nr得到PID 20341的数值超大,就是因为这个命令把所有线程的重复FD条目都统计进去了,才会误以为MongoDB占用了27万+FD,实际是个假象。

如果要排查too many open files错误,优先看/proc/<pid>/fd的数量,或者用上面提到的过滤后的lsof命令。

内容的提问来源于stack exchange,提问作者Liqang Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:17:41