You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何低影响获取与任务管理器一致的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 09:55:31