Linux 下系统当前打开的文件句柄总数由 /proc/sys/fs/file-nr 的第二个值给出,Windows 下需调用 NtQuerySystemInformation 获取;跨平台不推荐遍历进程统计,因存在竞态、权限、性能及语义偏差问题。

Linux 下用 /proc/sys/fs/file-nr 查看系统级句柄总数
Linux 没有“系统当前打开的句柄总数”这个统一 API,但 /proc/sys/fs/file-nr 提供了三元组:已分配未使用的句柄数、已使用句柄数、最大允许句柄数。真正反映“当前打开总数”的是第二个值。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 直接读取:
cat /proc/sys/fs/file-nr,输出类似1234 5678 98304,其中5678就是当前已打开的文件句柄总数(含 socket、pipe、普通文件等) - 在 C++ 中可用
std::ifstream读取该路径,再用std::istringstream解析第二项,避免依赖 shell 命令 - 注意:该值是全系统统计,不是单进程;且部分内核版本(如某些 5.x)中第一个数可能恒为 0,以第二项为准更可靠
- 不要误用
/proc/sys/fs/file-max——它只是上限,不是当前用量
Windows 下调用 NtQuerySystemInformation 获取句柄计数
Windows 没有公开的 Win32 API 返回全局句柄总数,必须调用未文档化的 NtQuerySystemInformation 并传入 SystemHandleInformation 类型。虽然风险可控(该函数长期稳定),但需手动解析返回结构体。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 包含头文件:
#include <winternl.h>,并链接ntdll.lib - 调用前先用
NtQuerySystemInformation试探缓冲区大小(返回STATUS_INFO_LENGTH_MISMATCH),再分配足够内存重试 - 返回的
SYSTEM_HANDLE_INFORMATION结构体数组长度不固定,需按NumberOfHandles字段遍历,其值即为当前系统句柄总数 - 权限要求:进程需以
SeDebugPrivilege权限运行,否则调用会失败(错误码STATUS_ACCESS_DENIED) - 不要尝试用
CreateToolhelp32Snapshot+Process32Next累加各进程句柄——它无法获取系统线程、内核驱动等持有的句柄,结果严重偏低
C++ 跨平台封装时为何不推荐实时聚合所有进程句柄数
有人试图在 Linux 上遍历 /proc/[pid]/fd/ 目录统计每个进程的 fd 数量再求和,或在 Windows 上枚举所有进程并调用 NtQueryObject。这种做法看似直观,实际问题很多。
关键原因:
- 竞态严重:/proc 下目录可能瞬间消失(进程退出),
opendir或FindFirstFile失败率高,导致计数跳变甚至 crash - 权限限制:非 root / 非管理员用户无法读取多数进程的
/proc/[pid]/fd/或打开其句柄,结果漏掉大量系统进程 - 性能开销大:Linux 上遍历上万个
/proc/[pid]/fd/目录,平均耗时 >200ms;Windows 枚举+逐个查询句柄,常超 500ms - 语义偏差:系统级句柄总数 ≠ 所有进程 fd 数之和(例如内核内部 socket 缓冲区、event 对象等不归属任何用户进程)
监控场景下更实用的替代方案
如果你真实需求是“判断系统是否快耗尽句柄”,而不是追求绝对精确的瞬时总数,有更轻量、更稳定的路径。
推荐做法:
- Linux:持续监控
/proc/sys/fs/file-nr的第二项与第三项比值,当超过 85% 时告警;同时观察/proc/sys/fs/inode-nr,inode 耗尽也会导致 open 失败(错误ENOSPC) - Windows:改用
Performance Counter查询\Objects\Handles计数器,无需提权,API 稳定(PdhAddCounter+PdhCollectQueryData),且自带采样缓存机制 - 应用层兜底:在自己的服务中用 RAII 封装资源(如自定义
FileHandle类),配合原子计数器记录本进程创建/关闭行为,比系统级扫描更准、更快、更可调试 - 注意:
ulimit -n只影响单进程软限制,不能代表系统总容量;lsof | wc -l输出含表头和重复行,直接计数不可靠
系统句柄总数本身是个模糊指标——内核实现细节、统计时机、权限边界都会影响数值。比起纠结一个瞬时数字,盯住增长趋势、结合错误日志(如 EMFILE、ERROR_TOO_MANY_OPEN_FILES)做响应,才是工程落地的关键。


















