应使用NtQuerySystemInformation(SystemExtendedHandleInformation, 64)获取系统全局句柄总数,需提权、动态加载ntdll、两次调用;PDH或遍历进程为次选方案。

如果您需要在 C++ 程序中实时获取 Windows 系统当前全局句柄引用总数,用于监控、统计或异常分析,则需调用 Windows 内核对象管理相关 API。以下是实现该功能的多种可行接口方案:
一、使用 NtQuerySystemInformation(未公开 NT API)
该方法通过调用 nt.dll 中的 NtQuerySystemInformation 函数,传入 SystemHandleInformation 类型参数,可枚举系统中所有进程打开的句柄信息,并累加计数。此方式返回的是全系统范围的句柄总数,精度高但依赖未公开接口,需手动加载函数地址。
1、使用 GetModuleHandleA 获取 ntdll.dll 模块句柄。
2、调用 GetProcAddress 获取 NtQuerySystemInformation 函数指针。
3、定义 SYSTEM_HANDLE_INFORMATION 结构体(含 HandleCount 字段及后续句柄数组)。
4、首次调用传入 NULL 缓冲区以获取所需缓冲区大小,再分配足够内存重试。
5、遍历返回的句柄条目,按进程 ID 分组或直接累计总数,注意每次调用后必须释放分配的缓冲区内存。
二、使用 Performance Data Helper(PDH)API
该方法通过 Windows 性能计数器访问“Process”和“Thread”对象下的“Handle Count”实例,对所有活动进程句柄数求和。虽为公开稳定接口,但存在采样延迟与权限限制,适用于非实时监控场景。
1、调用 PdhOpenQuery 开启一个新的性能查询句柄。
2、调用 PdhAddCounter 添加 \Process(*)\Handle Count 计数器路径。
3、调用 PdhCollectQueryData 触发一次数据采集。
4、调用 PdhGetFormattedCounterValue 获取长整型数值并累加各实例值,需过滤掉 Idle 和 _Total 实例以避免重复计算。
5、调用 PdhCloseQuery 释放查询资源。
三、遍历所有进程并调用 GetProcessHandleCount
该方法通过 EnumProcesses 获取全部活动进程 ID,对每个进程打开句柄(OpenProcess)后调用 GetProcessHandleCount 获取其当前句柄数。需 PROCESS_QUERY_INFORMATION 权限,且部分系统保护进程会拒绝打开。
1、调用 EnumProcesses 获取进程 ID 数组及实际数量。
2、对每个 PID 调用 OpenProcess,申请 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ 权限。
3、若 OpenProcess 成功,则调用 GetProcessHandleCount 获取该进程句柄数并加入总和。
4、调用 CloseHandle 关闭打开的进程句柄,失败时跳过该进程,不可中断整个统计流程。
5、释放进程 ID 数组内存。
四、读取 ETW 事件流中的句柄创建/关闭事件
该方法通过启用 Kernel Trace Provider 的 Handle Create/Close 事件,实时捕获并维护一个原子计数器。适用于长期运行的监控服务,可提供毫秒级变化追踪,但实现复杂度高且需管理员权限启动 ETW 会话。
1、调用 StartTrace 启动名为 “HandleMonitorSession” 的 ETW 会话。
2、调用 EnableTraceEx2 启用 Microsoft-Windows-Kernel-Handle 提供程序,筛选 Level=5 事件。
3、注册 EventRecordCallback 回调函数,解析 EVENT_RECORD 中的 HandleOperation 字段。
4、在回调中根据 OperationType 增减全局 std::atomic
5、调用 ControlTrace 停止会话前确保回调已退出,必须在回调内完成原子操作,禁止阻塞或调用同步 I/O。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











