linux下读取/proc/self/io的read_bytes字段可获进程自启动以来从块设备实际读取的字节数,需用unsigned long long解析,注意沙盒限制及内核版本差异。

Linux 下读取 /proc/self/io 的 read_bytes 字段
Linux 内核通过 /proc/[pid]/io 暴露进程 I/O 统计,其中 read_bytes 表示该进程自启动以来从块设备(如磁盘)实际读取的字节数(不含缓存命中)。这是最直接、开销最低的方式。
- 必须以文本方式读取该文件,逐行解析;
read_bytes:行后跟的是十进制整数,可能极大(需用unsigned long long) - 注意:该值包含所有块设备读取(如 SSD、HDD、NVMe),但不包括内存映射文件(mmap)的页缺失触发的读取——那些计入
pgpgin,而非read_bytes - 常见错误是直接
fopen("/proc/self/io", "r")后用fgets但未检查是否匹配到read_bytes:行,导致返回随机值或旧缓存 - 示例片段:
std::ifstream io("/proc/self/io");<br>std::string line;<br>while (std::getline(io, line)) {<br> if (line.substr(0, 11) == "read_bytes:") {<br> auto pos = line.find(':');<br> if (pos != std::string::npos) {<br> return std::stoull(line.substr(pos + 1));<br> }<br> }<br>}
Windows 下调用 GetProcessIoCounters 获取 ReadTransferCount
Windows 提供 GetProcessIoCounters API,其返回的 IO_COUNTERS 结构中 ReadTransferCount 字段即为累计磁盘读取字节数(同样不含缓存命中,仅实际设备 I/O)。
- 必须传入当前进程句柄:
GetCurrentProcess(),不能用NULL或其他无效句柄,否则调用失败且GetLastError()返回ERROR_INVALID_HANDLE -
ReadTransferCount是ULONGLONG类型,C++ 中对应unsigned long long;若用 32 位变量接收会截断 - 该计数器在 Windows Vista+ 才完全可靠;XP 或 Server 2003 下可能返回 0 或不准确
- 示例关键调用:
IO_COUNTERS counters;<br>if (GetProcessIoCounters(GetCurrentProcess(), &counters)) {<br> bytes = counters.ReadTransferCount;<br>}
跨平台封装时要注意的陷阱
不同系统统计口径存在本质差异:Linux read_bytes 是内核级块设备读计数,Windows ReadTransferCount 是 I/O 管理器汇总值,两者都绕过 page cache,但具体实现层细节不可比。
- 不要试图对两个值做差值计算“增量”,因为它们起始基准、更新时机、精度粒度均不同;同一进程在双系统下数值必然不等
- 频繁轮询(如每毫秒)会导致大量 syscalls,Linux 下反复 open/read
/proc/self/io开销显著;建议最小采样间隔 ≥ 100ms - 某些容器环境(如 Docker with pid namespace)中,
/proc/self/io可能被挂载为只读或不可见,需 fallback 到/proc/[pid]/io并确认 pid 是否为宿主机视角 - 没有标准 C++ 库函数可替代,必须条件编译:
#ifdef _WIN32/#else,不可依赖第三方库(如 Boost.Process)自动适配——它底层仍是调用上述原生接口
为什么不能用 statvfs 或 getrusage?
statvfs 返回的是整个文件系统的空闲/总空间,与进程无关;getrusage(RUSAGE_SELF) 的 ru_inblock 字段统计的是“块读次数”(512 字节为单位),不是字节数,且在多数现代 Linux 发行版中该字段恒为 0 —— 内核已弃用此统计项。
- 误用
ru_inblock * 512得到的值毫无意义,既不准确也不更新 - macOS 完全不支持
ru_inblock,返回值始终为 0 - 试图从
/sys/fs/cgroup/.../io.stat读取(cgroups v1/v2)虽可行,但需 root 权限、路径动态拼接、格式多变,远不如/proc/self/io稳定直接
实际使用时,最常被忽略的是:Linux 下 read_bytes 不包含 direct I/O 失败后的重试读取,而 Windows 的 ReadTransferCount 包含所有成功完成的读请求字节数——哪怕应用层重试了三次,只算最后一次成功传输的量。这个语义差异常导致监控曲线出现非预期跳变。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











