商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 系统应用 > Linux怎么查看具体的文件句柄泄漏追踪记录

Linux怎么查看具体的文件句柄泄漏追踪记录

  发布于2026-08-15 阅读(0)

扫一扫,手机访问

需要立刻提高警觉的 FD 行,通常有这么几类:一是持续递增的数字,比如1024r、1025r;二是 TYPE=REG 且 NAME 中带有(deleted);三是 TYPE=anon_inode/pipe,且数量和线程数明显强相关;四是 TYPE=sock、STATE=ESTABLISHED,但业务逻辑里又找不到对应连接;五是 TYPE=DIR 指向临时目录;六是 NAME 为空,或者直接显示为 socket:[xxx]。

Linux怎么查看具体的文件句柄泄漏追踪记录

lsof -p PID 输出里哪些 FD 行值得立即警惕

正常进程的 FD 列集中在 0u1w2wcwdmemDEL 或少量数字(如 15u)。一旦发现以下模式,基本可判定存在泄漏:

  • FD 列持续出现大量递增数字(如 1024r1025r1026w…),且 NAME 指向同一类路径(如 /tmp/xxx.log/var/log/app/*.log
  • TYPE=REG + NAME(deleted),且数量随时间增长 → 文件已被 unlink 但句柄未关,磁盘空间不释放
  • TYPE=anon_inodepipe 数量与线程数强相关(如每多一个线程就多 2 个 pipe + 1 个 eventpoll)→ 常见于未退出的 Looper、epoll 或异步 I/O 初始化未清理
  • TYPE=sockSTATE=ESTABLISHED 但无业务逻辑对应 → 可能是 HTTP 客户端连接池未 close,或 socket 未 shutdown
  • TYPE=DIR 指向临时目录(如 /tmp/upload_abc)→ 检查代码中是否用 Files.list()new File(dir).listFiles() 后没关闭 StreamDirectoryStream
  • NAME 为空或显示 socket:[1234567] → 这类句柄需结合 /proc/PID/fd/ 下实际符号链接反查,用 ls -l /proc/PID/fd/ | grep socket

为什么单次 lsof 看不到泄漏,但 still get “Too many open files”

这是最易踩坑的点:lsof 默认只显示当前打开的句柄,但某些泄漏是“瞬时创建 + 长期持有”,而 lsof 快照无法捕捉趋势。更关键的是:lsof 本身可能因 DNS 解析卡住,导致输出失真或漏项。

  • 必须加 -n(禁用 DNS 解析)和 -P(禁用端口名解析),否则排查过程可能引入干扰
  • 单次 lsof -p PID | wc -l 只是快照,无法判断趋势。应执行 watch -n 5 'lsof -n -P -p PID | wc -l',观察 30 秒内是否稳定或缓慢爬升(>5 行/秒即异常)
  • 同时运行 lsof -n -P -p PID 2>/dev/null | grep -E "^(ja va|python|node)" | head -20,确认新增句柄是否集中于某类文件(如全是 .jar.pycsocket
  • 若怀疑日志轮转问题,重点比对 lsof -n -P -p PID | grep "access.log"ls -la /var/log/nginx/access.log*,看是否还在写旧文件

怎么用 /proc/PID/fd 验证 lsof 没显示的句柄

lsof 有时会过滤掉某些内核抽象资源(比如部分 anon_inode 或容器环境中的 fd),而 /proc/PID/fd/ 是内核直接暴露的符号链接视图,更真实、无过滤。

  • 执行 ls -l /proc/PID/fd/,你会看到类似 1024 -> socket:[1234567]1025 -> anon_inode:[eventfd] 的条目
  • 对可疑 fd,用 readlink /proc/PID/fd/1024 获取原始类型;再配合 cat /proc/PID/status | grep -i fdsize 查看当前 fd 总数是否接近 ulimit -n 设置值
  • 若发现大量 socket:[*]anon_inode:[*],且数量与线程数/连接数匹配,大概率是未调用 close() 或未触发资源自动释放(如 Ja va 中未用 try-with-resources)
  • 注意:普通用户访问 /proc/PID/fd/ 需要目标进程属主权限,否则会提示 Permission denied;此时必须用 sudo

定位到泄漏源头后,怎么确认是不是代码没关资源

光看出现在哪类 fd 不够,得确认它是否真的来自你控制的代码路径。很多泄漏藏在标准库封装之下,比如 Files.list()ZipInputStream、HTTP 客户端默认连接池、甚至日志框架的异步刷盘线程。

  • Ja va 场景下,重点关注 Files.list()Files.walk()ZipFileSocketChannel.open() —— 它们都返回需显式关闭的资源,不能只靠 GC
  • Python 场景下,检查 open() 是否配对 close(),或是否用了 withos.scandir() 同样需 close()subprocess.Popenstdout/stderr 也容易漏关
  • Node.js 场景下,fs.createReadStream()http.request()net.createConnection() 都需显式 .destroy() 或监听 close 事件
  • 不要只盯文件路径——很多泄漏根本不出现在 NAME 列,而是表现为 TYPE=sockTYPE=anon_inode,这时要回溯调用栈,看是否在循环中反复 new client 但没 close
真正难的不是发现 fd 在涨,而是确认那个 socket:[1234567]anon_inode:[eventpoll] 谁创建的、谁该负责关、为什么没关。这时候 lsof/proc/PID/fd/ 只是入口,最终还得靠代码上下文和资源生命周期契约。
本文转载于:https://www.php.cn/faq/2987787.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注