翼度科技»论坛 编程开发 .net 查看内容

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

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
计数器、WMI

获取设备的内存信息,如系统可用运行内存:
  1. 1     public static async Task<double> GetMemoryAvailableAsync(FileSizeUnit fileSizeUnit = FileSizeUnit.GB)
  2. 2     {
  3. 3         return await Task.Run(() =>
  4. 4         {
  5. 5             using var managementClass = new ManagementClass("Win32_PerfFormattedData_PerfOS_Memory");
  6. 6             using var instances = managementClass.GetInstances();
  7. 7             double available = 0;
  8. 8             foreach (var mo in instances)
  9. 9             {
  10. 10                 //AvailableMBytes单位是MB
  11. 11                 var size = long.Parse(mo.Properties["AvailableMBytes"].Value.ToString()) * 1024 * 1024;
  12. 12                 available += size.ConvertTo(fileSizeUnit);
  13. 13             }
  14. 14
  15. 15             return available;
  16. 16         });
  17. 17     }
复制代码
以上是ManagementClass方式实现,还有ManagementObjectSearcher,都是WMI检索查询。
WMI查询比较慢,上面一段耗时在200ms+。
还有一种用的较多的,PerformanceCounter性能计数器,以CPU获取为例:
  1. 1     public static async Task<double> GetUsageByCounterAsync()
  2. 2     {
  3. 3         //CPU计数器
  4. 4         using var pcCpuUsage = new PerformanceCounter("Processor", "% Processor Time", "_Total") { MachineName = "." };
  5. 5         // NextValue首次会返回0,所以需要加个延时下次再获取值
  6. 6         pcCpuUsage.NextValue();
  7. 7         await Task.Delay(TimeSpan.FromMilliseconds(500));
  8. 8         var cpuUsed = pcCpuUsage.NextValue();
  9. 9         return cpuUsed;
  10. 10     }
复制代码
性能计数器,也有一定的耗时40ms以上。另外因为它实现方式,初始化后无法第一次获取到真正数值,需要间隔一段时间再去拿。所以此方案实际耗时挺高
WMI、性能计数器,昨天遇到了使用异常:

 

看源码,计数器是注册表PerformanceData位置损坏了,而Management是IWbemServices获取状态码ErrorCode异常。
PerformanceCounter是WMI,而WMI是基于WBEM协议实现的,所以我理解成上面的异常其实是一类问题。
官网有对此类异常有一些描述:重新生成性能计数器库值 - Windows Server | Microsoft Learn 

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

kernel32下有个函数可以获取内存状态
  1. 1     [DllImport("kernel32.dll")]
  2. 2     [return: MarshalAs(UnmanagedType.Bool)]
  3. 3     static extern bool GlobalMemoryStatusEx(ref MEMORYINFO mi);
复制代码
以下是获取可用运行内存的实现:
  1.     //Define the information structure of memory
  2.     [StructLayout(LayoutKind.Sequential)]
  3.     struct MEMORYINFO
  4.     {
  5.         public uint dwLength; //Current structure size
  6.         public uint dwMemoryLoad; //Current memory utilization
  7.         public ulong ullTotalPhys; //Total physical memory size
  8.         public ulong ullAvailPhys; //Available physical memory size
  9.         public ulong ullTotalPageFile; //Total Exchange File Size
  10.         public ulong ullAvailPageFile; //Total Exchange File Size
  11.         public ulong ullTotalVirtual; //Total virtual memory size
  12.         public ulong ullAvailVirtual; //Available virtual memory size
  13.         public ulong ullAvailExtendedVirtual; //Keep this value always zero
  14.     }
  15.     /// <summary>
  16.     /// Get the current memory usage
  17.     /// </summary>
  18.     /// <returns></returns>
  19.     private static MEMORYINFO GetMemoryStatus()
  20.     {
  21.         MEMORYINFO memoryInfo = new MEMORYINFO();
  22.         memoryInfo.dwLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(memoryInfo);
  23.         GlobalMemoryStatusEx(ref memoryInfo);
  24.         return memoryInfo;
  25.     }
  26.     /// <summary>
  27.     /// 获取系统可用运行内存
  28.     /// </summary>
  29.     /// <param name="fileSizeUnit">默认单位GB</param>
  30.     /// <returns></returns>
  31.     public static double GetMemoryAvailable(FileSizeUnit fileSizeUnit = FileSizeUnit.GB)
  32.     {
  33.         var memoryStatus = GetMemoryStatus();
  34.         var memoryAvailable = ((long)memoryStatus.ullAvailPhys).ConvertTo(fileSizeUnit);
  35.         return memoryAvailable;
  36.     }
复制代码
上述方式,获取速度超快,几乎不耗时。
通过Kernel32方式,获取CPU信息(CPU比例计算逻辑,代码略多点):
  1. 1     /// <summary>
  2. 2     /// 获取CPU占用率/使用率(单位:%)
  3. 3     /// </summary>
  4. 4     /// <returns></returns>
  5. 5     public static async Task<double> GetUsageByKernelAsync()
  6. 6     {
  7. 7         long idleTime1 = 0;
  8. 8         long kernelTime1 = 0;
  9. 9         long userTime1 = 0;
  10. 10         if (GetSystemTimes(out var lpIdleTime, out var lpKernelTime, out var lpUserTime))
  11. 11         {
  12. 12             idleTime1 = lpIdleTime;
  13. 13             kernelTime1 = lpKernelTime;
  14. 14             userTime1 = lpUserTime;
  15. 15         }
  16. 16         //添加俩次获取CPU信息的间隔
  17. 17         await Task.Delay(TimeSpan.FromSeconds(0.5));
  18. 18         long idleTime2 = 0;
  19. 19         long kernelTime2 = 0;
  20. 20         long userTime2 = 0;
  21. 21         if (GetSystemTimes(out var lpIdleTime2, out var lpKernelTime2, out var lpUserTime2))
  22. 22         {
  23. 23             idleTime2 = lpIdleTime2;
  24. 24             kernelTime2 = lpKernelTime2;
  25. 25             userTime2 = lpUserTime2;
  26. 26         }
  27. 27         //分别获取到用户时间、内核时间、空闲时间
  28. 28         var userTime = userTime2 - userTime1;
  29. 29         var kernelTime = kernelTime2 - kernelTime1;
  30. 30         var idleTime = idleTime2 - idleTime1;
  31. 31         //计算Cpu占用率。计算公式:用户时间+内核时间-空闲时间/用户时间+内核时间
  32. 32         var systemTotal = kernelTime + userTime;
  33. 33         var cpu = (systemTotal - idleTime) * 10000 / systemTotal;
  34. 34         return cpu / 100.0;
  35. 35     }
  36. 36
  37. 37     /// <summary>
  38. 38     /// 获取系统CPU时间数据
  39. 39     /// </summary>
  40. 40     /// <param name="lpIdleTime">空闲时间</param>
  41. 41     /// <param name="lpKernelTime">内核时间</param>
  42. 42     /// <param name="lpUserTime">用户时间</param>
  43. 43     /// <returns></returns>
  44. 44     [DllImport("kernel32.dll", SetLastError = true)]
  45. 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的内部源码,我标注了下:

所以ComputerInfo,也是基于GlobalMemoryStatusEx函数做了封装,大家可以直接用。
 
参考列表:
How to get system specs (processor, memory etc...) in C#? (microsoft.com)Get the CPU Usage in C# | Delft StackC#获取CPU和内存使用率 - 雨水的命运 - 博客园 (cnblogs.com)Determine CPU usage of current process (C++ and C#) | Philosophical GeekGet CPU Usage with GetSystemTimes - CodeProject 
出处:http://www.cnblogs.com/kybs0/本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
来源:https://www.cnblogs.com/kybs0/archive/2023/02/23/17146941.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具