如何低影响获取与任务管理器一致的CPU及内存使用率?
问题:获取与任务管理器一致的远程CPU/内存使用率,避免远程执行时CPU骤升
需求是获取和Windows任务管理器一致的内存使用率(RAM %)和CPU使用率(CPU %),目前通过C#调用PowerShell远程执行脚本实现,但远程目标机器的CPU使用率会骤升。现有实现未使用PerformanceCounter是因为无法获取计算所需的% Processor Performance数值,现寻求替代方案,询问是否只能依赖WMI。
现有实现代码
PowerShell脚本(GetResources.ps1)
$mem = cmd.exe /c 'wmic ComputerSystem get TotalPhysicalMemory && wmic OS get FreePhysicalMemory'; $loadpc = cmd.exe /c 'wmic cpu get loadpercentage'; $maxclock = cmd.exe /c 'wmic cpu get maxclockspeed'; $cpuperf = (Get-Counter -Counter '\Processor Information(_Total)\% Processor Performance').CounterSamples.CookedValue; $mem,$loadpc,$maxclock,$cpuperf
C#执行代码
private static List<double> GetResourceUsages(string hostname) { string output = (LaunchProcess("powershell.exe", "-command Invoke-Command -ComputerName " + hostname + " -FilePath '<path>\\GetResources.ps1'")); output = RemoveSubstrings(new List<string>() { "TotalPhysicalMemory", "FreePhysicalMemory", "LoadPercentage", "-", "MaxClockSpeed", " " }, output); List<string> list = output.Split("\r\n").ToList(); for (int i = 0; i < list.Count; i++) { if (list[i].Length == 0) { list.RemoveAt(i); i--; } } long.TryParse(list[0], out long MaxRAM); long.TryParse(list[1], out long AvailableRAM); double RAMUsage = (double)100 - ((double)AvailableRAM / (((double)MaxRAM) / 1024) * (double)100); Double.TryParse(list[2], out double loadPC); Double.TryParse(list[3], out double baseClock); Double.TryParse(list[4], out double perfPC); double CurrentCPUClock = (perfPC / 100) * baseClock; double CPUUtilization = loadPC / ((baseClock / CurrentCPUClock) * 100) * 100; return new List<double>() { RAMUsage, CPUUtilization }; }
替代解决方案
1. 优化现有PowerShell脚本,降低进程开销
原脚本多次调用cmd.exe和wmic,频繁创建进程导致CPU飙升。改成直接用PowerShell的Get-CimInstance访问WMI,减少进程创建:
# 直接通过CIM获取硬件信息,避免多次启动外部进程 $computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem $os = Get-CimInstance -ClassName Win32_OperatingSystem $cpu = Get-CimInstance -ClassName Win32_Processor $cpuPerf = (Get-Counter -Counter '\Processor Information(_Total)\% Processor Performance').CounterSamples.CookedValue # 直接输出所需数值,减少后续文本处理的复杂度 $computerSystem.TotalPhysicalMemory, $os.FreePhysicalMemory, $cpu.LoadPercentage, $cpu.MaxClockSpeed, $cpuPerf
2. 直接在C#中使用WMI/CIM API,完全避免外部进程调用
使用Microsoft.Management.Infrastructure(CIM)或System.Management直接远程访问WMI,不需要启动PowerShell或cmd,性能大幅提升:
using System; using System.Collections.Generic; using Microsoft.Management.Infrastructure; using System.Diagnostics; using System.Threading; private static List<double> GetResourceUsagesViaCim(string hostname) { var resourceUsages = new List<double>(); const string cimNamespace = @"root\cimv2"; // 建立远程CIM会话(可复用会话减少连接开销) var sessionOptions = new CimSessionOptions(); using (var cimSession = CimSession.Create(hostname, sessionOptions)) { // 获取总物理内存 var computerSystemInstances = cimSession.QueryInstances(cimNamespace, "WQL", "SELECT TotalPhysicalMemory FROM Win32_ComputerSystem"); long totalPhysicalMemory = 0; foreach (var instance in computerSystemInstances) { totalPhysicalMemory = (long)instance.CimInstanceProperties["TotalPhysicalMemory"].Value; instance.Dispose(); } // 获取可用物理内存 var osInstances = cimSession.QueryInstances(cimNamespace, "WQL", "SELECT FreePhysicalMemory FROM Win32_OperatingSystem"); long freePhysicalMemory = 0; foreach (var instance in osInstances) { freePhysicalMemory = (long)instance.CimInstanceProperties["FreePhysicalMemory"].Value; instance.Dispose(); } // 计算内存使用率(和任务管理器逻辑一致) double ramUsage = 100 - ((double)freePhysicalMemory / ((double)totalPhysicalMemory / 1024) * 100); resourceUsages.Add(ramUsage); // 获取CPU基础信息 var cpuInstances = cimSession.QueryInstances(cimNamespace, "WQL", "SELECT LoadPercentage, MaxClockSpeed FROM Win32_Processor"); double cpuLoadPercentage = 0; double cpuMaxClockSpeed = 0; foreach (var instance in cpuInstances) { cpuLoadPercentage = (uint)instance.CimInstanceProperties["LoadPercentage"].Value; cpuMaxClockSpeed = (uint)instance.CimInstanceProperties["MaxClockSpeed"].Value; instance.Dispose(); } // 远程获取% Processor Performance计数器(之前的问题可能是权限或路径错误) using (var perfCounter = new PerformanceCounter( "Processor Information", "% Processor Performance", "_Total", hostname)) { // 第一次获取通常为0,等待后再获取一次 Thread.Sleep(100); double cpuPerformance = perfCounter.NextValue(); // 计算CPU使用率(和任务管理器逻辑一致) double currentCpuClock = (cpuPerformance / 100) * cpuMaxClockSpeed; double cpuUtilization = cpuLoadPercentage / ((cpuMaxClockSpeed / currentCpuClock) * 100) * 100; resourceUsages.Add(cpuUtilization); } } return resourceUsages; }
3. 是否只能依赖WMI?
不是必须,但WMI/CIM是Windows原生的远程管理接口,成熟可靠且无需额外部署。其他可选方案包括:
- 直接使用Windows Remote Management (WinRM)的REST API,但本质仍基于WMI
- 读取系统性能计数器的底层数据(难度较高,无原生API支持)
- 第三方系统监控库(但可能引入依赖)
WMI/CIM仍是最直接、高效的原生解决方案。
额外优化建议
- 复用CIM/WMI会话,避免每次请求都建立新连接
- 合并WQL查询,减少远程请求次数
- 缓存性能计数器实例,避免频繁创建销毁
内容的提问来源于stack exchange,提问作者Unknown
相关产品推荐
相关产品推荐

