推荐用 FILE*(fopen+fgets),因其简单可控、避免编码异常;VmRSS 才是当前真实内存占用,代表物理内存驻留页数,单位 kB 需×1024 转字节。

读取 /proc/self/status 需要用 std::ifstream 还是 FILE*?
用 std::ifstream 更自然,但得注意它默认不处理换行符差异(Linux 是 \n,没问题),且不能直接跳过空行或解析键值对。实际中更推荐用 C 风格的 fopen+fgets:简单、可控、避免 std::ifstream 在遇到非 UTF-8 字节时意外 failbit。
-
/proc/self/status是纯 ASCII 文本,每行形如VmRSS: 12345 kB,没有 BOM,无编码风险 - 别用
std::getline后调.find(':')就完事——某些字段(如MMUPageSize)可能带空格,冒号不是唯一分隔符 - 优先用
fgets读整行,再用strtok或手动找第一个:+ 跳过空白,比正则或流迭代器轻量得多
VmRSS 和 VmSize 哪个才是“当前真实内存占用”?
VmRSS(Resident Set Size)代表进程当前真正驻留在物理内存中的页数,是监控内存压力最相关的指标;VmSize(Virtual Memory Size)只是虚拟地址空间总大小,含 mmap 区域、未分配的堆预留、甚至被 mmap(MAP_NORESERVE) 占用却没实际映射的地址——它不反映真实内存压力。
-
VmRSS单位是kB,需提取数字后转成字节(×1024)才方便和其他内存统计对比 -
VmHWM(High Water Mark)记录 RSS 历史峰值,适合判断是否发生过内存尖峰,但只读一次拿不到动态变化 - 不要把
VmData/VmStk直接加起来当“堆栈内存”——它们是估算值,且和sbrk或mmap分配行为不严格对应
解析时容易漏掉的字段和格式陷阱
字段名后面不一定只有一个空格:VmPeak: 后可能是 7 个空格,Threads: 后可能是制表符,voluntary_ctxt_switches: 这种长字段名中间还有下划线。硬写 substr(0, 8) == "VmRSS:" 会失败。
- 必须从行首开始匹配字段名+冒号+任意空白(
\s*),再取之后所有非空白字符作为值(strspn+strcspn更稳) -
CapEff:、Seccomp:等字段值是十六进制字符串(如0000000000000000),误当十进制会溢出 - 遇到
Uid:行(Uid: 1000 1000 1000 1000)别只取第一个数——这是 real/effective/saved/fs uid,通常你只关心第一个
要不要加 std::this_thread::sleep_for 避免频繁读取?
不用主动 sleep,但得知道 /proc/self/status 不是实时快照:内核在 open 时刻生成快照,后续 read 返回的是该时刻状态。连续两次读取间隔小于 10ms,结果几乎不变;但若每毫秒读一次,IO 开销不大,瓶颈其实在字符串解析本身。
- 单次读取耗时约 5–15μs(SSD/内存文件系统下),远低于一次
malloc或函数调用开销 - 真正要防的是在 tight loop 里反复
fopen+fclose——改用单次fopen+ 多次fseek(..., SEEK_SET)+rewind更高效 - 如果用于调试日志,建议加个 100ms 采样间隔;若用于内存泄漏检测,应配合
mallinfo或malloc_stats对比使用,单靠VmRSS无法区分是程序分配还是系统缓存
解析逻辑本身不复杂,难的是字段语义边界和长期运行时的数值漂移——比如 VmRSS 突然涨了 20MB,到底是你的 vector 扩容,还是内核回收了 page cache 导致进程被强制多驻留?这时候就得看 VmData 和 cat /proc/meminfo | grep -i "commit" 的配合了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











