linux下应读取/proc/[pid]/stat第10列(minflt)和第12列(majflt)获取软硬缺页累计次数,二者之和为总页错误数;解析时须跳过含空格括号的comm字段,避免字段错位。

Linux下用/proc/[pid]/stat获取页错误统计
/proc/[pid]/stat 文件第10列(minflt)是次要缺页次数,第12列(majflt)是主要缺页次数。两者之和就是总页错误数。C++里读取它只需打开文件、按空格分割、提取对应字段:
常见错误现象:直接用 std::stoi 转换第10或12个字段失败——因为 /proc/[pid]/stat 的第2字段是进程命令名,含空格和括号(如 (bash)),导致字段错位。
正确做法是逐字符解析,或用 std::regex 匹配数字序列;更稳妥的是跳过前两个字段后,再按空格切分剩余部分:
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
long get_page_faults() {
std::ifstream f("/proc/self/stat");
std::string line;
if (!std::getline(f, line)) return -1;
std::istringstream iss(line);
std::vector<:string> fields;
std::string field;
while (iss >> field) fields.push_back(field);
// 字段索引从 0 开始:minflt 是第 9 个(索引 9),majflt 是第 11 个(索引 11)
if (fields.size()
<h3>Windows下用GetProcessMemoryInfo获取页面错误数
Windows没有直接暴露“页错误次数”的API,但 <code>GetProcessMemoryInfo</code> 返回的 <code>PROCESS_MEMORY_COUNTERS</code> 结构体中,<code>PageFaultCount</code> 字段就是自进程启动以来的总页错误数(含软硬缺页)。
</h3>
<p>使用场景:跨平台代码中需条件编译;注意该值是累计值,不是瞬时速率。</p>
<p>容易踩的坑:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul>
<li>必须链接 <code>psapi.lib</code>,否则链接失败</li>
<li>
<code>PROCESS_MEMORY_COUNTERS</code> 大小随系统变化,应始终用 <code>sizeof()</code> 初始化 <code>cb</code> 成员</li>
<li>32位程序在64位系统上运行时,若未定义 <code>_WIN32_WINNT</code> ≥ 0x0500,可能获取不到完整字段</li>
</ul>
<pre class="brush:php;toolbar:false;">
#ifdef _WIN32
#include <windows.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
long get_page_faults() {
PROCESS_MEMORY_COUNTERS pmc;
pmc.cb = sizeof(pmc);
if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
return -1;
return static_cast<long>(pmc.PageFaultCount);
}
#endif
</long></psapi.h></windows.h>
为什么不能用getrusage或clock_gettime
getrusage(RUSAGE_SELF, &ru) 的 ru.ru_majflt 和 ru.ru_minflt 理论上也提供页错误数,但它在某些内核配置下(如禁用 CONFIG_TASKSTATS)返回 0,且 glibc 有时会缓存旧值,不保证实时更新。
性能影响:相比读 /proc/self/stat(纯内存映射文件,无系统调用开销),getrusage 是系统调用,有上下文切换成本;而 clock_gettime 根本不提供页错误信息,混淆它是因为名字带“time”就误以为能统计资源事件。
参数差异:
-
/proc/self/stat:零开销,字段位置固定(但需小心解析) -
GetProcessMemoryInfo:Windows 唯一可靠途径,PageFaultCount是 DWORD 类型,32位溢出风险极低(需连续触发约43亿次缺页) -
getrusage:POSIX 标准但实现不稳定,不推荐用于生产监控
注意子进程与线程的统计边界
页错误计数是**进程粒度**的,不是线程或作用域局部的。fork 出的子进程有独立计数,但线程共享同一进程的 minflt/majflt。
容易被忽略的地方:如果你在多线程程序中高频调用该函数并做差值来估算某段代码的缺页开销,结果会包含其他线程同期触发的缺页——无法隔离归因。
真正想测一段逻辑的内存访问效率,应该用 perf stat -e page-faults ./your_program 这类外部工具,而非依赖进程级累计值。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










