計數器、WMI 獲取設備的記憶體信息,如系統可用運行記憶體: 1 public static async Task<double> GetMemoryAvailableAsync(FileSizeUnit fileSizeUnit = FileSizeUnit.GB) 2 { 3 return awai ...
計數器、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、性能計數器,昨天遇到了使用異常:
看源碼,計數器是註冊表PerformanceData位置損壞了,而Management是IWbemServices獲取狀態碼ErrorCode異常。
PerformanceCounter是WMI,而WMI是基於WBEM協議實現的,所以我理解成上面的異常其實是一類問題。
官網有對此類異常有一些描述:重新生成性能計數器庫值 - Windows Server | Microsoft Learn
所以基於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-GetSystemTimes方式,獲取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的內部源碼,我標註了下:
所以ComputerInfo,也是基於GlobalMemoryStatusEx函數做了封裝,大家可以直接用。
關鍵字:【Kernek32-GlobalMemoryStatusEx】【Kernek32-GetSystemTimes】
參考列表:
How to get system specs (processor, memory etc...) in C#? (microsoft.com) Get the CPU Usage in C# | Delft Stack C#獲取CPU和記憶體使用率 - 雨水的命運 - 博客園 (cnblogs.com) Determine CPU usage of current process (C++ and C#) | Philosophical Geek Get CPU Usage with GetSystemTimes - CodeProject作者:唐宋元明清2188 出處:http://www.cnblogs.com/kybs0/ 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須在文章頁面給出原文連接,否則保留追究法律責任的權利。