直接盯 /proc/pid/fd/ 目录数量变化最有效,单次快照无意义;需用 watch -n 1 'ls /proc/pid/fd/ | wc -l' 观察趋势,持续增长即表明fd泄漏,配合 lsof -p pid 识别异常fd类型(如递增数字、(deleted)、anon_inode、sock established等)定位根源。

直接盯 /proc/PID/fd/ 目录数量变化最有效
泄漏是动态过程,单次快照毫无意义。ls /proc/<pid>/fd/ | wc -l</pid> 只是起点,必须观察趋势:
- 先记下初始值:
ls /proc/<pid>/fd/ | wc -l</pid> - 立刻执行:
watch -n 1 'ls /proc/<pid>/fd/ | wc -l'</pid>,每秒刷新一次 - 数字稳定不动 → 基本排除泄漏;持续 +1、+2 或跳变 → 就是它
-
watch默认高亮变化行,比手动敲命令省眼力,也避免误读
lsof -p PID 里哪些 FD 行值得立即警惕
正常进程的 FD 列集中在 0u、1w、2w、cwd、mem、DEL 或少量数字(如 15u)。以下模式基本等于泄漏信号:
-
FD列持续出现大量递增数字(如1024r、1025w…),且NAME指向同一类路径(如/tmp/xxx.log) -
TYPE=REG+NAME含(deleted)→ 文件被unlink但句柄未关,磁盘空间不释放 -
TYPE=anon_inode或pipe数量与线程数强相关(比如每多一个线程就多 2 个pipe+ 1 个eventpoll)→ 常见于未退出的 Looper、epoll 初始化未清理 -
TYPE=sock+STATE=ESTABLISHED但无业务逻辑对应 → 可能是 HTTP 客户端连接池没close,或 socket 没shutdown -
NAME为空 或 显示socket:[1234567]→ 需结合ls -l /proc/<pid>/fd/ | grep socket</pid>反查真实目标
用 perf trace 或 strace 确认 open/close 是否成对
靠人肉扫代码效率极低,优先用系统级跟踪验证调用是否匹配:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 推荐:
perf trace -e syscalls:sys_enter_openat,syscalls:sys_enter_close -p <pid></pid>,实时抓系统调用流 - 备选:
strace -p <pid> -e trace=open,openat,close,closefrom 2>&1 | grep -E "(open|close)"</pid>,加-v可看参数(如路径、返回 fd) - 特别注意:C/C++ 进程若 fork 后子进程不操作父进程 fd,又没设
FD_CLOEXEC,这些 fd 就变成“幽灵句柄” - Java 进程别迷信
try-with-resources:JNI 创建的 socket、eventfd 等 native 资源,若没在Cleaner或finalize中显式close,照样泄漏
为什么 lsof 看不到泄漏,但 still get “Too many open files”
这是最易踩坑的点:lsof 默认只显示当前打开的句柄,而有些泄漏是“瞬时创建 + 长期持有”,比如:
- 短连接频繁创建后未释放(尤其 REST 调用密集场景),
lsof快照可能刚好错过峰值 - 某些
anon_inode类型(如timerfd、eventfd)生命周期长但不显式出现在文件路径中 -
lsof自身卡住:不加-n(禁 DNS 解析)和-P(禁端口名解析),输出可能失真或阻塞 - 真正有效的对比方式是:
watch -n 5 'lsof -p <pid> | wc -l'</pid>观察 30 秒内是否缓慢爬升(>5 行/秒即异常)
真正难的不是看到数字涨,而是分辨涨的是哪类资源——socket、anon_inode、REG (deleted) 各自指向完全不同的代码层问题,不能只盯着总数。漏掉 NAME 列的细节,就等于把线索扔进垃圾桶。










