PageFaultCount是进程启动以来的累计页错误次数,非实时速率且不区分软/硬错误,不能直接用作页错误率;需结合性能计数器(如\Process()\Page Faults/sec)或ETW获取实时硬页错误。

GetProcessMemoryInfo 的 PageFaultCount 字段能直接用吗
不能直接当“页错误率”用。PageFaultCount 是自进程启动以来的累计值,单位是次数,不是每秒或每毫秒的速率。它不区分软页错误(soft fault)和硬页错误(hard fault),而工控或高实时场景真正关心的是硬页错误——即必须从磁盘换入的缺页,这会引发毫秒级延迟甚至抖动。
常见误用是拿两次 GetProcessMemoryInfo 的差值除以时间间隔,以为得到“率”。但问题在于:
-
PageFaultCount在 Windows 上更新频率低(通常只在内核统计周期触发时刷新,非实时) - 它包含所有线程的页错误,无法过滤出当前线程或关键路径的异常突增
- 数值本身无上下文:100 次/秒对后台服务可能正常,对数控插补线程就是危险信号
Windows 下真正可用的实时页错误监控路径
要接近实时(≤ 100ms 级别)且区分硬/软页错误,必须绕过 GetProcessMemoryInfo,改用 Windows Performance Counter API:
- 计数器路径:
\Process(<process_name>)\Page Faults/sec</process_name>—— 这是系统级每秒硬+软页错误总和,更新粒度由性能计数器采样周期决定(默认约 15ms) - 更精准的硬页错误指标:
\Memory\Pages Input/sec+\Memory\Pages Output/sec,这两个反映实际磁盘 I/O 引发的页换入换出,是硬页错误的强代理 - 必须用
PdhOpenQuery+PdhAddCounter初始化,不能靠轮询GetProcessMemoryInfo - 注意进程名带空格或特殊字符时,计数器路径需转义,例如
MyApp v2.1要写成MyApp^ v2.1
为什么 PageHeap 不适合做运行时页错误监控
PageHeap 是调试工具,不是监控接口。它启用后会让每次 malloc/new 分配额外保护页并强制对齐,显著拖慢内存分配路径——在数控系统或高频数据采集场景下,这会导致定时任务超期、加工轨迹抖动。
立即学习“C++免费学习笔记(深入)”;
它的设计目标是捕获越界写(如 p[5] = 1 写到 8 字节分配的第 6 字节),而非统计页错误。一旦触发保护页访问,进程直接崩在 ACCESS_VIOLATION,你收不到“页错误率”,只收到一个 dump 文件。
典型误操作:
- 在 Release 模式下启用
pageheap /enable myapp.exe 0x01—— 性能下降 3–5 倍,且部分优化编译会绕过 PageHeap hook - 把 PageHeap 当作生产环境内存健康探针 —— 它没有 API 返回当前错误计数,只能靠崩溃日志反推
- 混淆
PageHeap和内核页错误:前者是用户态 heap corruption 检测,后者是 VM 子系统处理的缺页异常,二者不在同一层级
工控/数控场景下真正可行的轻量方案
在内存受限、实时性敏感的嵌入式 IPC 或数控上位机中,推荐组合使用:
- 每 500ms 调用一次
GetProcessMemoryInfo,提取PageFaultCount差值,仅用于趋势告警(如连续 3 次增幅 >200%) - 同时监听
\Process(<name>)\WorkingSetSize</name>,若工作集持续收缩但页错误上升,大概率是硬页错误+内存压力 - 避免在中断服务例程(ISR)或硬实时线程中调用任何性能计数器 API —— 它们可能触发 APC 或等待内核对象
- 若需字节级精度(如定位某次插补计算引发的缺页),必须结合 ETW(Event Tracing for Windows)开启
Microsoft-Windows-Kernel-Memoryprovider,但开销不可忽略
最易被忽略的一点:Windows 的 PageFaultCount 不包含驱动层引发的页错误(如显卡驱动映射显存失败),这类错误会走不同路径,需单独查 WMI 的 Win32_PerfFormattedData_PerfOS_Memory 类中 PageReadsPerSec 字段。


















