挂起前“too many open files”错误需依次检查:服务systemd日志(journalctl -u)、全系统错误日志(journalctl -p err)、内核日志(dmesg)、应用stderr日志;确认fd泄漏要分析/proc/pid/fd/链接重复性,而非仅看总数;lsof可能漏掉a_inode等内核对象,应以/proc/pid/fd/为准;strace需加-f并跟踪所有fd相关系统调用,关注返回值匹配。

系统挂起前“Too many open files”错误在哪看
挂起前通常不是突然崩溃,而是先出现 Too many open files 错误,这个错误会出现在应用日志、系统日志或内核日志里,但位置不统一,得挨个查。
-
journalctl -u your-service-name --since "2 hours ago":优先查服务自己的 systemd 日志,错误常以 errno 24(EMFILE)形式出现,比如open() failed: Too many open files -
journalctl -p err --since "2 hours ago" | grep -i "open files":全系统级别筛选错误级日志,覆盖未托管到 systemd 的进程 -
dmesg | tail -50:内核日志里有时会打印pid XXX comm XXX reached limit on open files,尤其在 ulimit 被硬限制卡死时 - 如果应用自己记录了 stderr,检查其日志文件中是否含
errno=24或Bad file descriptor——注意EBADF(errno 9)往往是 fd 泄漏后误用已关闭 fd 导致的次生错误,不是泄漏本身
/proc//fd 目录里哪些线索说明正在泄漏
光看数量增长不够,得确认是不是同个资源被反复打开却没关 —— 这才是泄漏的铁证。
PyCharm 2026.2.0.1 Linux版提供 JetBrains 官方 2026.2.0.1 版本安装包,适合需要指定 PyCharm 版本进行 Python 项目开发、运行和调试的用户。
- 执行
ls -l /proc/<pid>/fd/ | head -20</pid>,重点观察软链接目标是否大量重复,例如几十个-> /dev/xxx或-> socket:[1234567]指向同一个 inode 或设备号 - 用
ls -l /proc/<pid>/fd/ 2>/dev/null | awk '{print $11}' | sort | uniq -c | sort -nr | head -5</pid>快速统计最常出现的目标路径,若某设备节点或 socket 出现上百次,基本就是泄漏点 - 注意
a_inode类型(如eventfd、anon_inode):这类无法直接看到路径,但若数量异常增长且与业务逻辑中频繁创建的资源(如 timerfd、signalfd)匹配,也要怀疑 - 别只看总数:
ls /proc/<pid>/fd/ | wc -l</pid>是当前 fd 数,但得对比 enable/disable 操作前后变化量 —— 单次操作净增 3 个 fd,重复 10 次就泄露 30 个
为什么 lsof -p 有时看不到泄漏源头
lsof 显示的是 fd 的“语义信息”,但某些 fd 内核不提供可读路径,导致输出全是 a_inode 或 REG 无名项,容易误判为没泄漏。
- 常见于内核模块驱动节点(如
/dev/mydrv)、memfd_create 创建的匿名内存文件、或 eventfd/timerfd 等内核对象 —— 它们在lsof中显示为a_inode,但ls -l /proc/<pid>/fd/</pid>仍能看到数字编号和指向 -
lsof -p <pid> | grep -E "(a_inode|CHR|REG)"</pid>只能帮你分类,不能替代/proc/<pid>/fd/</pid>的原始链接分析 - 如果
lsof输出行数远少于ls /proc/<pid>/fd/ | wc -l</pid>,说明大量 fd 未被识别,此时必须回到/proc/<pid>/fd/</pid>目录手动 inspect - 某些容器环境或 seccomp 限制下,
lsof可能因权限不足漏掉部分 fd,而/proc/<pid>/fd/</pid>只要进程属于当前用户就可读
strace 跟踪 open/close 时最容易忽略的三个细节
用 strace 抓调用链很有效,但默认参数容易错过关键上下文。
- 必须加
-f:否则只跟踪主进程,漏掉 fork 出的子进程或线程里的 fd 操作 - 不要只 trace
open,得包含openat、socket、pipe、epoll_create等所有可能分配 fd 的系统调用 ——strace -e trace=open,openat,socket,pipe,epoll_create,close,dup,dup2 -f -p <pid></pid> - 输出日志体积大,建议用
-o trace.log -s 256:-s 控制字符串截断长度,否则路径太长会被省略,看不到具体文件名;-o 避免刷屏丢失早期调用 - 注意返回值:成功调用返回非负整数(即 fd 号),失败返回 -1 并设
errno;重点找那些返回 fd 却没对应close(fd)的调用对
a_inode 后不确定哪个该关、哪个是正常复用。这时候得结合代码路径判断:比如某个模块每次初始化都调 eventfd() 却没配对 close(),哪怕它在 lsof 里看起来都一样,也是泄漏。










