Linux无句柄概念,只有文件描述符(fd),线程共享进程级fd表;fd泄漏指open/socket等未close致fd耗尽,可用strace、/proc/pid/fdinfo等定位,RAII封装可预防,valgrind等内存工具无法检测fd泄漏。

Linux下没有“句柄”概念,只有文件描述符(fd)
Windows 的 Handle、CreateEvent、CloseHandle 在 Linux 对应的是 open/socket/eventfd 等系统调用,以及统一的 close。所谓“线程句柄泄漏”,实际是线程中反复 open、socket、epoll_create、timerfd_create 等却未 close,导致进程级文件描述符耗尽。
Linux 进程 fd 限制默认常为 1024 或 65536(可通过 ulimit -n 查),一旦打满,open 返回 -1、socket 失败、epoll_ctl 报 EMFILE——这不是内存泄漏,是资源耗尽,现象更直接、更急迫。
- 用
ls /proc/<pid>/fd | wc -l</pid>实时看 fd 总数,比ps或top更准 - 不要依赖
lsof -p <pid></pid>查实时增长:它本身会短暂打开大量 fd,干扰观测;且默认不显示 fd 类型来源(如是否来自eventfd) - 注意:线程不“拥有”独立 fd 表,所有线程共享进程级 fd 表;所谓“线程泄漏”,本质是某线程创建后忘了关,或异常路径跳过了
close
定位 fd 持续增长的具体类型和位置
单纯知道总数涨没用,得确认是哪类 fd 在涨、谁开的、在哪开的。
- 用
cat /proc/<pid>/fdinfo/<fd_num></fd_num></pid>查单个 fd 的详细信息:pos、flags、mnt_id,关键看type字段(如pipe、sock、eventfd、inotify) - 结合
strace -p <pid> -e trace=open,openat,socket,accept,eventfd,timerfd_create,close</pid>实时抓系统调用,过滤出高频open但无对应close的线程 tid(strace输出首列即 tid) - 若程序带调试符号,可附加
gdb -p <pid></pid>后执行thread apply all bt,重点检查阻塞在read/epoll_wait的线程——它们往往持有一堆未关闭的 fd,尤其是循环中accept后只处理不close
代码层如何避免线程中 fd 泄漏
C++ 没有 Windows 那样的 RAII 句柄封装惯用法,但可以自己建轻量包装,强制配对。
在无 root/sudo 权限的环境(云容器、VPS、隔离主机)中安装并配置 OpenClaw 浏览器工具的 headless Chrome。适用场景:...
立即学习“C++免费学习笔记(深入)”;
- 别裸用
int fd = socket(...);写个FileDescriptor类,构造传 fd,析构自动close(fd),并禁用拷贝(只允许移动) - 对
epoll_create1、eventfd、timerfd_create等也做同样封装,避免“只开不关”逻辑散落在多处 - 特别警惕异常路径:线程函数里
socket成功后,若后续connect失败抛异常,fd就漏了——必须用try/catch或 RAII 包装兜底 - 检查第三方库:如某些网络库(libev、muduo)内部管理 fd,但若你手动调用了
ev_io_set后又没调ev_io_stop,也可能导致底层 fd 未释放
为什么 valgrind 和 AddressSanitizer 对 fd 泄漏无效
valgrind --leak-check=full 和 -fsanitize=address 只监控堆内存(malloc/new),完全不感知内核资源如 fd、信号量、共享内存段。
- 它们报
definitely lost是指 malloc 出来的内存块没 free,和open出来的 fd 没 close 是两套机制、两个计数器 - 想让工具链覆盖 fd,得用
strace+ 自定义脚本统计,或上bpftrace写探针跟踪sys_enter_open和sys_exit_close的匹配情况 - 生产环境慎用
strace -f全局跟踪:它会让进程卡顿严重,且日志爆炸;更适合用perf trace -e syscalls:sys_enter_open,syscalls:sys_enter_close做低开销采样
真正难的不是发现 fd 在涨,而是确认哪个线程、哪次调用开的、为什么没关——这要求你既懂系统调用语义,又得能读通线程调度上下文,不能只盯着工具输出的数字。

















