应读取/proc/pid/smaps_rollup中所有private_字段(如private_anon、private_hugetlb等)之和并乘以1024得到精确rss字节数;内核低于4.5时需解析/proc/pid/smaps中带“private”标记的内存段,按mmupagesize与private_值计算;高频监控须用独立线程周期读取并存入原子变量。

在Linux系统中精确获取C++进程的私有物理内存(RSS)占用量,需绕过/proc/pid/stat中已过时的RSS字段,直接解析/proc/pid/smaps_rollup或逐页统计/proc/pid/smaps中的Private_*行,否则读到的是含共享库映射的粗略值,监控曲线会出现明显虚高。
读取smaps_rollup获取实时精确RSS
从Linux 4.5起,/proc/pid/smaps_rollup提供聚合后的内存统计,其中Private_Hugetlb和Private_Anon之和即为真正不与其他进程共享的物理内存总量。
第一步:打开/proc/self/smaps_rollup文件,以只读方式访问当前进程自身数据。
第二步:逐行扫描,匹配以"Private_"开头的行,提取冒号后空格后的数字(单位KB),累加所有Private_*字段值(包括Private_Anon、Private_Dirty、Private_Hugetlb、Private_Ksm等)。
第三步:将累加结果乘以1024得到字节数——【注意:smaps_rollup中数值单位固定为KB,不可误用page size换算】。
兼容旧内核:解析完整smaps逐页过滤
若目标系统内核低于4.5(如CentOS 7默认3.10),smaps_rollup不存在,必须遍历/proc/pid/smaps中每个内存段,仅统计标记为“private”的页。
方法一:按内存段循环解析
打开/proc/self/smaps → 读取每一段以“Size:”开头的节 → 遇到“MMUPageSize:”行时记录页大小 → 遇到“MMUPF:”行判断是否含“private”标记 → 若是,则取该段“MMUPageSize”对应行下方的“MMUPageSize * Private_”数值(单位页)→ 累加后乘以页大小得字节数。
方法二:跳过解析开销,直接grep提取(适合脚本辅助调试)
执行system("grep -E '^Private_|^MMUPageSize:' /proc/self/smaps > /tmp/smaps_priv") → 在C++中读取/tmp/smaps_priv → 按行配对:上一行是MMUPageSize N,下一行是Private_X: M → 则贡献内存为N × M × 1024字节。
构建低开销周期性监控器
高频读取/proc/self/smaps会触发内核内存统计锁,单次耗时可达毫秒级,不可在主循环中每毫秒调用。
启动一个独立std::thread,使用clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, …)实现严格间隔(如500ms)唤醒 → 每次唤醒仅执行一次smaps_rollup读取+累加 → 结果存入原子变量std::atomic
主线程通过load()读取该变量即可获得最新RSS值,避免重复解析开销。这一步操作起来很简单,直接把g_current_rss_bytes.load()嵌入性能日志或阈值判断逻辑里就行。
监控数据写入环形缓冲区(std::array<:pair uint64_t>, 1000>),满时覆盖最老条目 → 外部工具可通过mmap映射该缓冲区实现零拷贝导出。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











