std::chrono无法替代系统级性能计数,因其仅提供挂钟或线程时间,而CPU使用率、内存占用等需依赖平台特有接口(如Windows的GetSystemTimes、Linux的/proc/stat),跨平台封装须隔离差异并统一数据结构。

为什么不能直接用 std::chrono 做系统级性能计数?
std::chrono 提供的是“挂钟时间”或“线程运行时间”,但系统性能监控需要的是内核暴露的底层指标:CPU 使用率、内存占用、进程线程数、磁盘 I/O 等。这些在 Windows 和 Linux 上获取方式完全不同,std::chrono 无法替代。
跨平台封装的关键不是统一 API,而是隔离平台差异——把 Windows 的 GetSystemTimes / GlobalMemoryStatusEx 和 Linux 的 /proc/stat / /proc/meminfo 封装成一致的接口。
- Windows 下必须链接
psapi.lib,且GetSystemTimes需要SE_INCREASE_QUOTA_NAME权限(通常普通用户可读) - Linux 下读
/proc是轻量级的,但路径和字段格式不固定(如/proc/meminfo中MemAvailable:在旧内核可能不存在) - 不要试图用
std::filesystem判断/proc是否存在——它在 WSL 下存在,但原生 Windows 没有该目录,应通过编译宏区分
如何定义统一的性能数据结构?
结构体必须容纳所有平台共有的核心字段,并允许平台特有字段扩展。避免用 union 或虚函数——增加二进制大小且无必要。
struct SystemStats {
uint64_t cpu_idle_ms = 0; // 累计空闲时间(毫秒)
uint64_t cpu_kernel_ms = 0; // 累计内核态时间
uint64_t cpu_user_ms = 0; // 累计用户态时间
size_t memory_total_bytes = 0;
size_t memory_used_bytes = 0;
size_t process_count = 0;
#ifdef _WIN32
uint64_t io_read_bytes = 0;
uint64_t io_write_bytes = 0;
#endif
};- 所有字段用无符号类型,避免符号扩展问题(尤其在 32/64 位混用时)
- Linux 下
cpu_*时间需从/proc/stat的前几行解析,第一行为总时间,需减去 idle 时间再拆分 user/system - Windows 的
FILETIME是 100ns 单位,必须除以 10000 转为毫秒,且要调用FileTimeToULargeInteger正确转换
如何安全地做一次跨平台采样?
采样函数不能抛异常,也不能阻塞太久。Linux 下读 /proc 文件是原子的,但 Windows 的 GetSystemTimes 可能失败(例如权限不足),必须检查返回值。
立即学习“C++免费学习笔记(深入)”;
- Linux 版本优先使用
open()+read(),而非std::ifstream——避免 locale 解析干扰数字格式 - Windows 版本中,
GetSystemTimes返回FALSE时,应设所有 CPU 字段为 0 并记录错误(可通过GetLastError()判断是否为ERROR_ACCESS_DENIED) - 内存统计:Linux 用
MemTotal:和MemAvailable:;Windows 用MEMORYSTATUSEX.dwTotalPhys和dwAvailPhys,注意后者是“可用物理内存”,不是已用内存 - 进程数:Linux 读
/proc目录项数量(跳过非数字名);Windows 调用EnumProcesses获取 PID 数组长度
为什么两次采样相减才能得到利用率?
绝大多数系统指标是单调递增的累计值(如 CPU 时间、I/O 字节数),直接读取单次值没有意义。真正的 CPU 利用率 = (total_time - idle_time) / total_time,而这个 total_time 必须来自两次采样差值。
- 建议最小采样间隔 ≥ 100ms,否则 Windows 下
GetSystemTimes变化可能为 0,导致除零或结果失真 - Linux 下
/proc/stat每次读取都是瞬时快照,但字段顺序依赖内核版本(如 5.10+ 新增guest_nice),应按空格分割后跳过前缀匹配,而非硬编码索引 - 不要缓存第一次采样的原始值在类成员里——如果对象长期存活,中间发生系统休眠或时间跳变,差值会严重偏大
跨平台最难的部分不是代码写两份,而是让两套逻辑在语义上对齐:比如 “memory used” 在 Windows 是 dwTotalPhys - dwAvailPhys,在 Linux 是 MemTotal - MemAvailable,但两者并不完全等价(Linux 的 MemAvailable 包含可回收 slab,Windows 不区分)。这点必须在文档里写清楚,不能假装它们一致。



















