linux下读取/proc/[pid]/stat获取缺页次数,第10和12字段(非15、16)分别对应minor和major缺页累计值;需跳过前9个字段并注意第11字段为cminflt;更推荐用getrusage(rusage_self, &ru)直接获取ru.ru_minflt和ru.ru_majflt。

Linux下读取/proc/[pid]/stat里的缺页中断字段
Linux内核在/proc/[pid]/stat第15和第16个字段分别记录了当前进程的**次要缺页中断(minor page faults)**和**主要缺页中断(major page faults)**次数。这两个值是自进程启动以来的累计计数,单位为整数。
实操时注意:[pid]要替换成目标进程ID,比如当前进程可用getpid()获取;字段按空格分隔,但第2个字段(comm)本身可能含空格,所以必须按括号规则解析——实际应从第1个字段(pid)开始数,跳过第2个(被括号包裹的命令名),再往后数13个字段才是minor fault位置。
- 用
std::ifstream打开/proc/self/stat(查自己)或/proc/1234/stat(查其他进程,需权限) - 逐字符跳过前两个字段(第1个是数字,第2个是
(xxx)格式,需匹配右括号) - 再读取接下来的13个字段(到第15个字段为止),第14个是minor,第15个是major
- 字段间可能有多个空格,推荐用
std::istringstream配合>>提取,它自动跳过空白
用getrusage()获取进程资源使用统计
getrusage(RUSAGE_SELF, &ru)是POSIX标准接口,在大多数Linux发行版和glibc中可用,返回的struct rusage里ru_minflt和ru_majflt字段直接对应minor/major缺页中断次数,语义清晰、无需解析文本。
相比/proc/[pid]/stat,它更轻量、无字符串解析开销,且不受/proc挂载状态影响。但要注意:该调用只反映**调用时刻之前**的累计值,不支持采样差值计算(需自行缓存上一次值)。
- 包含头文件:
<sys></sys> - 声明
struct rusage ru;,调用后检查返回值是否为0 -
ru.ru_minflt是long类型,表示minor fault次数;ru.ru_majflt同理 - 若查子进程,可用
RUSAGE_CHILDREN,但仅对已wait()过的子进程有效
为什么minflt常远大于majflt,且变化频繁
minor fault指页表已存在映射、只需分配物理页并更新TLB(如首次访问刚mmap()的区域);major fault则需从磁盘(如swap或文件)加载数据,耗时高得多。因此,正常程序运行中minor fault大量发生是合理的——比如堆内存增长、栈扩展、共享库首次引用等。
但如果你观察到majflt持续上升,往往意味着内存压力大、频繁换入换出,或程序存在低效的随机访问模式(如遍历超大稀疏数组)。此时minflt也会同步上涨,但比例关系会变。
- 用
perf stat -e page-faults,minor-faults,major-faults ./a.out可交叉验证 - 注意:
perf统计的是事件发生次数,而/proc和getrusage是累计值,两者数值一致 - 某些容器环境(如cgroup v1)中,
getrusage可能被截断或延迟更新,优先以/proc/[pid]/stat为准
跨平台兼容性与权限限制
C++标准库不提供缺页中断接口,所有方案均依赖操作系统特性。Linux是唯一能稳定获取精确minor/major区分的主流平台;macOS的task_info()只返回总page fault数(pti_faults),无法拆分;Windows需用GetProcessMemoryInfo()查PageFaultCount,同样无细分。
权限方面:/proc/[pid]/stat对非自身进程需要ptrace权限(即同用户或root),否则读取失败(errno = EACCES);getrusage()查RUSAGE_SELF永远允许,但查其他进程PID会失败(除非是子进程且已wait)。
- 不要尝试在Windows或macOS上硬套Linux逻辑,会编译通过但返回0或-1
- 生产环境监控建议封装成条件编译:
#ifdef __linux__ - 容器中若禁用
procfs挂载(如proc:ro),/proc/self/stat仍可读,但/proc/[other]/stat不可见
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











