
PerformanceCounter 在 Windows 上读系统指标不是“能用就行”,而是必须严格按采样逻辑走,否则拿到的全是 0、负数或飘忽不定的假值。
为什么 NextValue() 第一次总返回 0 或异常?
这不是 bug,是设计使然:NextValue() 计算的是两次采样之间的差值除以时间间隔(类似导数),首次调用时没有前序基准,只能返回 0 或未定义值。
- 必须调用两次,且中间要有真实延时(不能 Sleep(1) 这种毫秒级抖动)
- CPU 和内存推荐间隔 500ms,磁盘 I/O 类(如
Bytes Read/sec)建议 ≥1000ms - 别在循环里每轮都 new 一个
PerformanceCounter—— 句柄泄漏快,且每次初始化都重置采样状态 - 若需高频采集(如每秒多次),复用实例 +
NextValue()即可,但要注意:连续调用间隔太短(
"Processor" 和 "Memory" 类别的关键参数怎么填?
拼错一个字母、大小写不对、实例名用空字符串或 "0",都会直接抛 InvalidOperationException。
- CPU 使用率:类别名
"Processor"(不是 "process" 或 "CPU"),计数器名"% Processor Time",实例名必须是"_Total"(不是 ""、"0" 或 "System") - 可用内存:类别名
"Memory",计数器名"Available MBytes",实例名""(空字符串,不是 "_Total")——这是少数几个不支持实例的计数器之一 - 别用
"% Committed Bytes In Use"算“内存占用率”,它反映的是虚拟内存提交比例,和任务管理器显示的物理内存使用率完全不等价
监控磁盘 I/O 时 "PhysicalDisk" 实例名怎么选?
直接写 "_Total" 最省事,但要注意它只聚合所有物理磁盘,不包含 NVMe 或某些 RAID 卷;想监控 C: 盘,不能硬写 "C:",得先查可用实例。
- 枚举实例:用
PerformanceCounterCategory.GetCategories().FirstOrDefault(c => c.CategoryName == "PhysicalDisk")?.GetCounters(),遍历结果找InstanceName含 "C:" 的项 -
"Bytes Read/sec"和"Avg. Disk Queue Length"必须用相同实例名,否则数据语义错位 -
Avg. Disk Queue Length是平均等待请求数,持续 >2(HDD)或 >1(SSD)才真正提示 I/O 瓶颈;单次采样值波动大,别拿它做瞬时告警 - 返回值单位是字节/秒,转 MB/s 要除以
1024 * 1024,不是 1000²
程序跑在容器或 Win10 家庭版上失败怎么办?
不是代码问题,是环境缺性能计数器支持。
- Win10/11 家庭版默认禁用性能计数器:以管理员身份运行
lodctr /R重载定义 - .NET Core 3.1+ / .NET 5+ 项目必须手动安装 NuGet 包
System.Diagnostics.PerformanceCounter,否则编译过、运行时报Category does not exist - Windows Server Core 或 Nano Server 镜像通常精简掉了计数器驱动,需换基础镜像或改用
GlobalMemoryStatusExP/Invoke 方案 - 权限不足时抛
UnauthorizedAccessException:普通用户默认可读多数计数器,但某些类别(如 ".NET CLR Memory")需要 Performance Monitor Users 组权限
真正难的不是写几行 NextValue(),而是理解每个计数器背后的数据来源、采样机制和平台约束。比如 "Available MBytes" 是内核实时快照,而 "% Processor Time" 是通过中断周期采样估算的 —— 它们根本就不是同一类测量逻辑。忽略这点,监控数据再“看起来正常”,也可能误导容量决策。











