C# 获取电脑内存、CPU信息

  • C# 获取电脑内存、CPU信息已关闭评论
  • 129 次浏览
  • A+
所属分类:.NET技术
摘要

获取设备的内存信息,如系统可用运行内存:以上是ManagementClass方式实现,还有ManagementObjectSearcher,都是WMI检索查询。


计数器、WMI

获取设备的内存信息,如系统可用运行内存:

 1     public static async Task<double> GetMemoryAvailableAsync(FileSizeUnit fileSizeUnit = FileSizeUnit.GB)  2     {  3         return await Task.Run(() =>  4         {  5             using var managementClass = new ManagementClass("Win32_PerfFormattedData_PerfOS_Memory");  6             using var instances = managementClass.GetInstances();  7             double available = 0;  8             foreach (var mo in instances)  9             { 10                 //AvailableMBytes单位是MB 11                 var size = long.Parse(mo.Properties["AvailableMBytes"].Value.ToString()) * 1024 * 1024; 12                 available += size.ConvertTo(fileSizeUnit); 13             } 14  15             return available; 16         }); 17     }

以上是ManagementClass方式实现,还有ManagementObjectSearcher,都是WMI检索查询。

WMI查询比较慢,上面一段耗时在200ms+。

还有一种用的较多的,PerformanceCounter性能计数器,以CPU获取为例:

 1     public static async Task<double> GetUsageByCounterAsync()  2     {  3         //CPU计数器   4         using var pcCpuUsage = new PerformanceCounter("Processor", "% Processor Time", "_Total") { MachineName = "." };  5         // NextValue首次会返回0,所以需要加个延时下次再获取值  6         pcCpuUsage.NextValue();  7         await Task.Delay(TimeSpan.FromMilliseconds(500));  8         var cpuUsed = pcCpuUsage.NextValue();  9         return cpuUsed; 10     }

性能计数器,也有一定的耗时40ms以上。另外因为它实现方式,初始化后无法第一次获取到真正数值,需要间隔一段时间再去拿。所以此方案实际耗时挺高

WMI、性能计数器,昨天遇到了使用异常:

C# 获取电脑内存、CPU信息

 C# 获取电脑内存、CPU信息

看源码,计数器是注册表PerformanceData位置损坏了,而Management是IWbemServices获取状态码ErrorCode异常。

PerformanceCounter是WMI,而WMI是基于WBEM协议实现的,所以我理解成上面的异常其实是一类问题。

官网有对此类异常有一些描述:重新生成性能计数器库值 - Windows Server | Microsoft Learn 

C# 获取电脑内存、CPU信息

所以基于PerformanceCounter、ManagementClass以及ManagementObjectSearcher的实现,有一定风险。

kernel32

kernel32下有个函数可以获取内存状态

1     [DllImport("kernel32.dll")] 2     [return: MarshalAs(UnmanagedType.Bool)] 3     static extern bool GlobalMemoryStatusEx(ref MEMORYINFO mi);

以下是获取可用运行内存的实现:

    //Define the information structure of memory     [StructLayout(LayoutKind.Sequential)]     struct MEMORYINFO     {         public uint dwLength; //Current structure size         public uint dwMemoryLoad; //Current memory utilization         public ulong ullTotalPhys; //Total physical memory size         public ulong ullAvailPhys; //Available physical memory size         public ulong ullTotalPageFile; //Total Exchange File Size         public ulong ullAvailPageFile; //Total Exchange File Size         public ulong ullTotalVirtual; //Total virtual memory size         public ulong ullAvailVirtual; //Available virtual memory size         public ulong ullAvailExtendedVirtual; //Keep this value always zero     }      /// <summary>     /// Get the current memory usage     /// </summary>     /// <returns></returns>     private static MEMORYINFO GetMemoryStatus()     {         MEMORYINFO memoryInfo = new MEMORYINFO();         memoryInfo.dwLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(memoryInfo);         GlobalMemoryStatusEx(ref memoryInfo);         return memoryInfo;     }     /// <summary>     /// 获取系统可用运行内存     /// </summary>     /// <param name="fileSizeUnit">默认单位GB</param>     /// <returns></returns>     public static double GetMemoryAvailable(FileSizeUnit fileSizeUnit = FileSizeUnit.GB)     {         var memoryStatus = GetMemoryStatus();         var memoryAvailable = ((long)memoryStatus.ullAvailPhys).ConvertTo(fileSizeUnit);         return memoryAvailable;     }

上述方式,获取速度超快,几乎不耗时。

通过Kernel32方式,获取CPU信息(CPU比例计算逻辑,代码略多点):

 1     /// <summary>  2     /// 获取CPU占用率/使用率(单位:%)  3     /// </summary>  4     /// <returns></returns>  5     public static async Task<double> GetUsageByKernelAsync()  6     {  7         long idleTime1 = 0;  8         long kernelTime1 = 0;  9         long userTime1 = 0; 10         if (GetSystemTimes(out var lpIdleTime, out var lpKernelTime, out var lpUserTime)) 11         { 12             idleTime1 = lpIdleTime; 13             kernelTime1 = lpKernelTime; 14             userTime1 = lpUserTime; 15         } 16         //添加俩次获取CPU信息的间隔 17         await Task.Delay(TimeSpan.FromSeconds(0.5)); 18         long idleTime2 = 0; 19         long kernelTime2 = 0; 20         long userTime2 = 0; 21         if (GetSystemTimes(out var lpIdleTime2, out var lpKernelTime2, out var lpUserTime2)) 22         { 23             idleTime2 = lpIdleTime2; 24             kernelTime2 = lpKernelTime2; 25             userTime2 = lpUserTime2; 26         } 27         //分别获取到用户时间、内核时间、空闲时间 28         var userTime = userTime2 - userTime1; 29         var kernelTime = kernelTime2 - kernelTime1; 30         var idleTime = idleTime2 - idleTime1; 31         //计算Cpu占用率。计算公式:用户时间+内核时间-空闲时间/用户时间+内核时间 32         var systemTotal = kernelTime + userTime; 33         var cpu = (systemTotal - idleTime) * 10000 / systemTotal; 34         return cpu / 100.0; 35     } 36  37     /// <summary> 38     /// 获取系统CPU时间数据 39     /// </summary> 40     /// <param name="lpIdleTime">空闲时间</param> 41     /// <param name="lpKernelTime">内核时间</param> 42     /// <param name="lpUserTime">用户时间</param> 43     /// <returns></returns> 44     [DllImport("kernel32.dll", SetLastError = true)] 45     static extern bool GetSystemTimes(out long lpIdleTime, out long lpKernelTime, out long lpUserTime);

另外,也有一种途径可以获取到内存信息,引用程序集Microsoft.VisualBasic,Microsoft.VisualBasic.Devices下有个ComputerInfo类

var physicalMemory = new Microsoft.VisualBasic.Devices.ComputerInfo().AvailablePhysicalMemory;

可以拿到可用内存、总内存,不过CPU信息是没有的。

ComputerInfo的内部源码,我标注了下:

C# 获取电脑内存、CPU信息

所以ComputerInfo,也是基于GlobalMemoryStatusEx函数做了封装,大家可以直接用。

 

参考列表: