应优先使用性能计数器“Process(_Total)Handle Count”,因其无需管理员权限、稳定可靠;若需更高精度且系统为Win8.1+,可选SystemExtendedHandleInformation;其他方法或需特权或兼容性较差。

如果您需要在 C++ 程序中实时获取 Windows 系统当前全局句柄引用总数,用于资源泄漏检测或系统级监控,则需调用 Windows 内核对象统计接口。以下是实现该功能的多种可行方式:
一、使用 NtQuerySystemInformation 获取句柄计数
该方法通过调用未公开但广泛兼容的 NTAPI 函数 NtQuerySystemInformation,请求 SystemHandleInformation 类型数据,遍历后累加所有进程的句柄数量,最终得到全局句柄引用总数。需加载 ntdll.dll 并手动解析返回结构。
1、声明 SYSTEM_HANDLE_INFORMATION 结构体,包含 HandleCount 字段及后续变长数组成员。
2、调用 NtQuerySystemInformation 获取所需缓冲区大小,分配足够内存(通常需重试两次)。
3、再次调用 NtQuerySystemInformation 填充结构体,检查返回状态是否为 STATUS_SUCCESS。
4、遍历结构体中每个 SYSTEM_HANDLE_TABLE_ENTRY_INFO 条目,按进程 ID 分组或直接累计总数。
5、返回累计值,注意:此调用需以管理员权限运行,否则可能返回 STATUS_ACCESS_DENIED。
二、读取性能计数器 \Process(_Total)\Handle Count
该方法利用 Windows 性能数据接口 PdhOpenQuery 和 PdhAddCounter,访问内建的性能计数器路径,获取系统级句柄总数,无需特权且稳定可靠。
1、调用 PdhOpenQuery 创建查询句柄。
2、调用 PdhAddCounter 添加计数器路径 "\Process(_Total)\Handle Count"。
3、调用 PdhCollectQueryData 触发一次数据采集。
4、调用 PdhGetFormattedCounterValue 获取 64 位整型数值。
5、调用 PdhCloseQuery 释放资源,该方式不依赖调试权限,普通用户态程序可直接使用。
三、解析 ZwQuerySystemInformation 的 SystemExtendedHandleInformation 变体
Windows 8.1 及以后版本支持 SystemExtendedHandleInformation,其返回结构包含更精确的引用计数字段(HandleCount),避免了旧结构中因重复句柄导致的统计偏差。
1、动态获取 ZwQuerySystemInformation 地址,确保与当前系统 ABI 兼容。
2、申请足够缓冲区,首次调用获取实际所需大小。
3、第二次调用填充 SYSTEM_HANDLE_INFORMATION_EX 结构体。
4、遍历 Entries 数组,对每个条目的 HandleCount 字段求和。
5、必须验证系统版本 ≥ Windows 8.1,否则该信息类返回 STATUS_INVALID_INFO_CLASS。
四、通过 WMI 查询 Win32_PerfFormattedData_PerfOS_Handle
该方法借助 Windows Management Instrumentation 接口,查询预格式化的句柄性能数据,适合跨平台监控脚本集成,无需链接 ntdll 或 pdh 库。
1、初始化 COM 库并设置安全上下文,调用 CoInitializeSecurity。
2、连接 ROOTCIMV2 命名空间,创建 IWbemServices 接口实例。
3、执行 WQL 查询 "SELECT HandleCount FROM Win32_PerfFormattedData_PerfOS_Handle"。
4、枚举 IWbemClassObject 返回结果,提取 HandleCount 属性值。
5、查询结果为瞬时快照值,非累计引用总数,但与性能计数器路径语义一致。
五、轮询所有进程并累加 NtQueryInformationProcess 的 HandleCount
该方法通过 EnumProcesses 获取全部进程 ID,对每个进程调用 NtQueryInformationProcess(ProcessHandleCount 类),汇总所有活跃进程的句柄数,适用于需区分进程粒度的场景。
1、调用 EnumProcesses 获取进程 ID 列表,过滤掉无效 PID(如 0、4)。
2、对每个 PID 调用 OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION)获取句柄。
3、调用 NtQueryInformationProcess,传入 ProcessHandleCount 信息类。
4、将每个进程返回的 HANDLE_COUNT_INFORMATION.HandleCount 累加。
5、需启用 SeDebugPrivilege 权限,否则 OpenProcess 将对多数进程失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











