GetProcessHandleCount 是 Windows 下获取当前进程内核对象句柄数最直接、轻量且准确的 API,仅需传入 GetCurrentProcess() 伪句柄,无需额外权限或开销,适用于实时监控但不适用于精确泄漏判定。

Windows下用 GetProcessHandleCount 获取句柄数最直接
在 Windows 平台,C++ 程序想查自己当前打开了多少内核对象句柄(比如文件、事件、互斥体、线程等),GetProcessHandleCount 是最轻量、最准确的 API。它不依赖 WMI 或性能计数器,也不需要打开自身进程句柄,调用即返回当前进程的句柄总数。
注意:这个值是近似实时的,但不是原子快照——内核在统计时可能有极短窗口的增减,对监控类场景足够用,但不能用于精确资源泄漏判定。
-
GetProcessHandleCount只接受一个参数:GetCurrentProcess()返回的伪句柄,无需额外权限 - 返回值为
BOOL,成功时通过输出参数pdwHandleCount写入数量,需传入非空指针 - 失败时返回
FALSE,可调用GetLastError()查错,但实际极少失败(除非传入非法指针)
#include <windows.h>
#include <iostream>
int main() {
DWORD handleCount;
if (GetProcessHandleCount(GetCurrentProcess(), &handleCount)) {
std::cout << "Current handle count: " << handleCount << "\n";
} else {
std::cerr << "GetProcessHandleCount failed: " << GetLastError() << "\n";
}
return 0;
}
为什么不用 NtQueryInformationProcess 或性能计数器
有人会想到用更底层的 NtQueryInformationProcess 调用 ProcessHandleCount 类信息,或读取性能计数器 \Process(_Total)\Handle Count。这两者都有明显缺陷:
-
NtQueryInformationProcess需要PROCESS_QUERY_INFORMATION权限,而GetCurrentProcess()默认没这个权限,得先用OpenProcess重新打开自己,多此一举且可能失败 - 性能计数器(Performance Counter)延迟高、采样间隔默认 1 秒以上,数值滞后明显;且
_Total实例会混入所有进程,必须指定进程名或 PID 实例,配置麻烦还容易匹配错 - WMI 查询
Win32_Process.HandleCount更慢,依赖服务、权限、COM 初始化,完全不适合高频或启动阶段检查
Linux/macOS 没有等价机制,别硬套
C++ 跨平台项目常误以为存在统一接口。实际上 Linux 和 macOS **没有“内核对象句柄数”这个概念**:Linux 的 fd 数(/proc/self/fd/ 目录项数)只反映文件描述符,不包括 pthread mutex、condvar、eventfd 等用户态或混合态资源;macOS 的 getdtablesize() 同样只管 fd。内核对象如 kqueue、dispatch_source_t、semaphore_t 均不计入该统计。
通过 SSH 隧道从 Android 设备在互联网上对 Windows PC 实现完整远程控制的设置与使用指南,适用于远程桌面访问、安全 RDP 等。
立即学习“C++免费学习笔记(深入)”;
所以如果你看到跨平台封装里用 getdtablesize() 或 scandir("/proc/self/fd", ...) 当作“句柄总数”,那是错的——它漏掉了绝大多数真正消耗内核资源的对象。
调试时发现句柄数异常增长,下一步该看什么
如果用 GetProcessHandleCount 发现数值持续上涨,说明有泄漏,但光看总数不够定位。此时应:
- 用 Process Explorer(Sysinternals 工具)附加进程,按 Handle Type 排序,重点关注
Event、Section、Thread、Key这些常见泄漏源 - 检查代码中是否漏掉
CloseHandle(),尤其在异常路径、早期 return、或goto跳转后 - 注意 C++ RAII 封装(如
std::unique_ptr配自定义 deleter)是否真在析构时调用了CloseHandle;有些第三方库(如旧版 Boost.Thread)曾存在句柄未关闭 bug - 避免在循环里反复创建再忽略句柄(比如连续调用
CreateEvent但不保存或关闭),这类问题在GetProcessHandleCount曲线上表现为阶梯式上升
句柄泄漏最难复现的是“只在特定路径触发 + 关闭逻辑被宏屏蔽”,所以运行时定期打点比事后分析更有效——别等程序卡死才想起来查。

















