PerformanceCounter 是 Windows 下 C# 获取 CPU 和内存使用率最稳定低开销方案;CPU 用 "Processor" 类别 "% Processor Time" 计数器(实例 "_Total"),内存需计算 (总物理内存 − Available MBytes) / 总物理内存,首次调用 NextValue() 后须延时 100–500ms 再取第二次值。

用 PerformanceCounter 读 CPU 和内存占用最直接
Windows 平台下,C# 获取实时 CPU 和内存使用率,PerformanceCounter 是最稳定、开销最小的选择。它直接对接系统性能计数器,不需要额外进程或 WMI 查询延迟,也不依赖管理员权限(只要访问性能计数器的普通用户权限即可)。
常见错误是直接 new 一个 PerformanceCounter 就调用 NextValue(),结果第一次总返回 0 或异常值——这是因为 NextValue() 是差分计算,至少需要两次采样间隔才能出有效值。
- CPU 占用必须用
"Processor"类别、"% Processor Time"计数器,实例名填"_Total"(不是"0"或空字符串) - 内存占用不能直接读“使用率”,得自己算:
Available MBytes除以Commit Limit或系统总物理内存(推荐后者,更直观) - 首次调用
NextValue()后,务必等待至少 100–500ms 再调第二次,否则值不可信 - 记得在
Dispose()或Close(),否则计数器句柄泄漏(尤其在循环监控中)
PerformanceCounter 初始化失败的几个典型原因
运行时报 InvalidOperationException: Category does not exist 或 UnauthorizedAccessException,基本就那几类问题:
- 目标机器没启用性能计数器服务(极少见,但 Win10/11 家庭版默认关闭):运行
lodctr /R命令重载计数器定义 - 程序以“仅限 .NET Core/.NET 5+”方式运行,但未添加
System.Diagnostics.PerformanceCounterNuGet 包(.NET Core 3.1+ 默认不包含) - 在容器(如 Windows Server Core 镜像)里跑,镜像精简掉了性能计数器支持,需手动安装或换方案
- 代码里写了
"process"拼错成"Process"(类别名区分大小写)或实例名用了"System"(实际应为"_Total")
内存占用率怎么算才接近任务管理器的值
任务管理器显示的“内存使用率” ≈ (Total Physical Memory − Available MBytes) / Total Physical Memory,不是看 Committed Bytes 或 Pool Paged Bytes。很多代码误用 "Memory\% Committed Bytes In Use",这个值反映的是虚拟内存提交比例,和用户感知的“内存吃满”完全不是一回事。
- 用
GlobalMemoryStatusExAPI(P/Invoke)能拿到ullTotalPhys和ullAvailPhys,最准,但要写平台调用 - 纯托管方案:先用
PerformanceCounter("Memory", "Available MBytes")读空闲量,再用Microsoft.VisualBasic.Devices.ComputerInfo.TotalPhysicalMemory(需引用 VB 运行时)或GC.GetTotalMemory(false)不适用(那是托管堆,不是系统内存) - 注意单位:所有
PerformanceCounter返回的是float,Available MBytes是 MB,但总内存要用字节,换算别漏乘1024 * 1024
短周期轮询(
每 200ms 调一次 NextValue(),CPU 值在 0% 和 95% 之间抖动,不是 bug,是计数器本身的采样机制决定的——它统计的是上一采样周期内的平均负载,周期越短,波动越大。
- 生产环境建议采样间隔 ≥ 500ms;若需平滑,可缓存最近 3–5 个值取移动平均(别简单用
Math.Round截断) - 不要在 UI 线程频繁更新(比如 WPF 的
DispatcherTimer每 100ms 刷一次),容易卡顿;改用Task.Run+await Task.Delay后再回调 UI - 如果只是做告警(比如 >80% 持续 3 秒),建议加状态机:只在值连续 N 次超阈值时触发,而不是每次超标都响应
真正难的不是读数值,是怎么定义“高负载”——CPU 短时飙升可能是正常 GC 或 JIT,内存缓慢上涨才更值得盯。监控逻辑比采集代码重要得多。











