GetProcessIoCounters 返回 FALSE 的最常见原因是权限不足或句柄无效:需确保进程句柄具有 PROCESS_QUERY_INFORMATION 权限、目标进程未退出、且非受保护进程(如 SYSTEM);查自身进程应使用 GetCurrentProcess() 而非 OpenProcess。

GetProcessIoCounters 为什么返回 FALSE?
调用 GetProcessIoCounters 失败(返回 FALSE)最常见原因是权限不足或句柄无效。该函数要求目标进程句柄至少拥有 PROCESS_QUERY_INFORMATION 权限,且不能是已退出的进程。
- 用
OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)获取句柄,不要漏掉PROCESS_QUERY_INFORMATION—— 仅PROCESS_QUERY_LIMITED_INFORMATION在 Win10 1607+ 虽可查基础 IO,但不保证兼容旧系统 - 若目标是其他用户进程(尤其 SYSTEM 或受保护进程),当前会话通常无权打开,
GetLastError()会返回ERROR_ACCESS_DENIED - 确保进程 PID 有效:刚
TerminateProcess后立即查,句柄可能已失效,GetLastError()返回ERROR_INVALID_HANDLE
如何正确读取当前进程的 IO 计数器
查自己进程最稳妥,无需额外权限。关键点是:必须用 GetCurrentProcess() 获取伪句柄,而非用 GetCurrentProcessId() 再去 OpenProcess —— 后者在低完整性级别(如 IE Protected Mode、沙盒)下可能失败。
-
GetCurrentProcess()返回的句柄默认带全权限,包括PROCESS_QUERY_INFORMATION - 结构体必须清零:
IO_COUNTERS io = {};,否则未初始化字段可能含垃圾值,导致后续计算异常 - Windows 仅保证
ReadTransferCount和WriteTransferCount在所有版本中可用;OtherTransferCount在某些 Server 版本或驱动过滤下可能为 0
IO_COUNTERS io = {};
if (GetProcessIoCounters(GetCurrentProcess(), &io)) {
printf("Read: %I64u bytes\n", io.ReadTransferCount);
printf("Write: %I64u bytes\n", io.WriteTransferCount);
}
ReadOperationCount 和 WriteOperationCount 是什么?
这两个字段统计的是「发起的 IO 请求次数」,不是字节数。一次 fread 调用可能触发多次底层 ReadFile,每次都会让 ReadOperationCount +1;同理,频繁小写(如日志逐行写)会让 WriteOperationCount 远高于 WriteTransferCount。
- 高操作计数 + 低传输字节 → 典型的小块随机 IO,比如数据库 WAL 日志刷盘、配置文件轮询读取
- 低操作计数 + 高传输字节 → 大块顺序 IO,比如视频文件流式读写
- 注意:这些计数包含所有内核态发起的 IO,包括内存映射文件(
CreateFileMapping)的页错误引发的磁盘加载,不一定对应用户层的ReadFile/WriteFile调用
跨平台替代方案为何不推荐直接用 GetProcessIoCounters
Linux/macOS 没有等价 API,需读 /proc/[pid]/io(Linux)或 libproc(macOS)。但如果你硬要在 Windows 上做跨平台抽象,别封装 GetProcessIoCounters 为“通用 IO 接口”——它只返回累计值,无法直接得出速率(如 MB/s);而 Linux 的 /proc/[pid]/io 同样是累计值,两次采样差值才得速率。
立即学习“C++免费学习笔记(深入)”;
- 想监控实时 IO 速率,必须自己定时采样(如 1s 间隔),再计算差值;Windows 本身不提供“每秒 IO 字节数”的现成接口
-
GetProcessIoCounters不区分磁盘类型(SSD/HDD/网络存储),也不分离缓存命中(file cache)与真实磁盘操作;要细化分析,得结合 ETW(Event Tracing for Windows)或PerfCounter中的Process\IO Data Operations/sec - 32 位程序在 64 位 Windows 上调用该函数,
IO_COUNTERS结构体内字段仍是 64 位整型,不会截断 —— 但需确保编译器没把结构体对齐搞错(VC++ 默认没问题)


















