直接读 /proc/meminfo 更靠谱,因其提供内核实时内存快照,而 sysconf(_SC_PHYS_PAGES) 返回启动时静态估算值,无法反映 swap、cgroup 限流、内存回收等运行时变化,尤其在容器/K8s 环境下是获取 cgroup-aware 内存数据的唯一可靠路径。

为什么直接读 /proc/meminfo 比调用 sysconf(_SC_PHYS_PAGES) 更靠谱
因为 /proc/meminfo 提供的是内核当前维护的实时内存快照,而 sysconf 类接口返回的是启动时静态估算值,不反映 swap、cgroup 限流、内存回收等运行时变化。尤其在容器或 k8s 环境下,/proc/meminfo 是唯一能拿到 cgroup-aware 内存数据的路径(只要进程在对应 cgroup 下,读的就是该 cgroup 的 /proc/meminfo)。
实操建议:
- 始终以只读方式打开
/proc/meminfo,避免因权限或挂载变化导致 open 失败 - 不要假设字段顺序——逐行扫描匹配
MemTotal:、MemAvailable:等前缀,而非按行号取值 -
MemAvailable:是 Linux 3.14+ 才有,老内核需退回到MemFree:+Buffers:+Cached:组合估算,但误差大
如何安全解析 MemAvailable 并转成字节数
字段值单位固定为 kB,但行尾可能带空格或制表符,且某些发行版(如部分嵌入式 busybox)会省略单位。直接 sscanf(line, "MemAvailable: %ld kB", &val) 容易失败。
实操建议:
- 用
std::string::find()定位"MemAvailable:",再用std::stoi()配合std::string::substr()提取数字部分,忽略后续非数字字符 - 捕获
std::invalid_argument和std::out_of_range异常,出错时 fallback 到MemFree - 注意:
MemAvailable是内核估算的“可立即分配”内存,含 page cache 可回收部分,比MemFree更贴近真实可用量
写日志时怎么避免阻塞主线程又不丢数据
频繁读 /proc/meminfo 本身开销极小(
实操建议:
- 用无锁队列(如
boost::lockfree::queue或自研环形缓冲区)暂存内存快照结构体,生产者只 push,不碰文件 - 单独起一个低优先级线程,批量读队列 + 合并格式化 +
writev()一次写入,减少系统调用次数 - 日志行必须带毫秒级时间戳(
std::chrono::steady_clock::now()),否则无法对齐其他指标(如 CPU 使用率) - 别用
std::ofstream默认构造——它默认带 full buffering,崩溃时最后一段日志大概率丢失
常见错误现象和绕过方法
现象:open("/proc/meminfo", O_RDONLY) 返回 -1,errno = ENOENT;或读到空内容;或 MemAvailable 字段不存在。
原因和对策:
- 容器中挂载了只读
/proc子集(如 docker run --read-only-proc)→ 改用/host/proc/meminfo(若挂载了 host proc)或降级读/sys/fs/cgroup/memory/memory.usage_in_bytes - 内核版本 /proc/sys/kernel/osrelease,fallback 到
MemFree + Buffers + Cached - Shmem粗略估算(注意Shmem是共享内存,不可回收) - 日志里出现负数内存值 → 未做 unsigned long long 转换,
stoll()解析超大数值时溢出,改用std::stoull() - 多线程并发读同一
FILE*导致乱码 → 每次都fopen/fclose,别复用句柄
最麻烦的其实是 cgroup v2 环境下 /proc/meminfo 不再反映当前 cgroup 限制——得切到 /sys/fs/cgroup/memory.current 和 /sys/fs/cgroup/memory.max。这点很容易被忽略,一上线就发现日志里的“可用内存”远大于实际允许值。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











