.net 要获取CPU和内存的使用率,一般是通过 PerformanceCounter 或者 WMI 查询得到,但是如果操作系统经常不正常断电或者别的什么原因,让系统的性能计数器抽风了,可能就会造成初始化 PerformanceCounter 对象出错。
性能计数器错误一般可以通过 lodctr /r 可以修复,但是时不时要这么搞一下,对用户总是太不友好了,所以能通过 Win32API 来获取也是一个不错的选项。
代码已封装到两个工具类 CpuUsageNt 和 MemUsage 里面了
''' <summary> ''' Inherits the CPUUsage class and implements the Query method for Windows NT systems. ''' </summary> ''' <remarks> ''' <p>This class works on Windows NT4, Windows 2000, Windows XP, Windows .NET Server and higher.</p> ''' </remarks> Private NotInheritable Class CpuUsageNt ''' <summary> ''' Initializes a new CpuUsageNt instance. ''' </summary> ''' <exception cref="NotSupportedException">One of the system calls fails.</exception> Public Sub New() Dim timeInfo(31) As Byte ' SYSTEM_TIME_INFORMATION structure Dim perfInfo(311) As Byte ' SYSTEM_PERFORMANCE_INFORMATION structure Dim baseInfo(43) As Byte ' SYSTEM_BASIC_INFORMATION structure Dim ret As Integer If (Environment.OSVersion.Platform <> PlatformID.Win32NT) Then Throw New NotSupportedException() End If ' get new system time ret = NtQuerySystemInformation(SYSTEM_TIMEINFORMATION, timeInfo, timeInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' get new CPU's idle time ret = NtQuerySystemInformation(SYSTEM_PERFORMANCEINFORMATION, perfInfo, perfInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' get number of processors in the system ret = NtQuerySystemInformation(SYSTEM_BASICINFORMATION, baseInfo, baseInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' store new CPU's idle and system time and number of processors _oldIdleTime = BitConverter.ToInt64(perfInfo, 0) ' SYSTEM_PERFORMANCE_INFORMATION.liIdleTime _oldSystemTime = BitConverter.ToInt64(timeInfo, 8) ' SYSTEM_TIME_INFORMATION.liKeSystemTime _processorCount = baseInfo(40) End Sub ''' <summary> ''' Determines the current average CPU load. ''' </summary> ''' <returns>An integer that holds the CPU load percentage.</returns> ''' <exception cref="NotSupportedException">One of the system calls fails. The CPU time can not be obtained.</exception> Public Function Query() As Integer Dim timeInfo(31) As Byte ' SYSTEM_TIME_INFORMATION structure Dim perfInfo(311) As Byte ' SYSTEM_PERFORMANCE_INFORMATION structure ' get new system time Dim ret As Integer = NtQuerySystemInformation(SYSTEM_TIMEINFORMATION, timeInfo, timeInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' get new CPU's idle time ret = NtQuerySystemInformation(SYSTEM_PERFORMANCEINFORMATION, perfInfo, perfInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' CurrentValue = NewValue - OldValue Dim dbIdleTime As Double = BitConverter.ToInt64(perfInfo, 0) - _oldIdleTime Dim dbSystemTime As Double = BitConverter.ToInt64(timeInfo, 8) - _oldSystemTime ' CurrentCpuIdle = IdleTime / SystemTime If dbSystemTime <> 0 Then dbIdleTime = dbIdleTime / dbSystemTime End If ' CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors dbIdleTime = 100.0 - dbIdleTime * 100.0 / _processorCount + 0.5 ' store new CPU's idle and system time _oldIdleTime = BitConverter.ToInt64(perfInfo, 0) ' SYSTEM_PERFORMANCE_INFORMATION.liIdleTime _oldSystemTime = BitConverter.ToInt64(timeInfo, 8) ' SYSTEM_TIME_INFORMATION.liKeSystemTime Return CInt(Fix(dbIdleTime)) End Function ''' <summary> ''' NtQuerySystemInformation is an internal Windows function that retrieves various kinds of system information. ''' </summary> ''' <param name="dwInfoType">One of the values enumerated in SYSTEM_INFORMATION_CLASS, indicating the kind of system information to be retrieved.</param> ''' <param name="lpStructure">Points to a buffer where the requested information is to be returned. The size and structure of this information varies depending on the value of the SystemInformationClass parameter.</param> ''' <param name="dwSize">Length of the buffer pointed to by the SystemInformation parameter.</param> ''' <param name="returnLength">Optional pointer to a location where the function writes the actual size of the information requested.</param> ''' <returns>Returns a success NTSTATUS if successful, and an NTSTATUS error code otherwise.</returns> <DllImport("ntdll", EntryPoint:="NtQuerySystemInformation")> Private Shared Function NtQuerySystemInformation(ByVal dwInfoType As Integer, ByVal lpStructure() As Byte, ByVal dwSize As Integer, ByVal returnLength As IntPtr) As Integer End Function ''' <summary>Returns the number of processors in the system in a SYSTEM_BASIC_INFORMATION structure.</summary> Private Const SYSTEM_BASICINFORMATION As Integer = 0 ''' <summary>Returns an opaque SYSTEM_PERFORMANCE_INFORMATION structure.</summary> Private Const SYSTEM_PERFORMANCEINFORMATION As Integer = 2 ''' <summary>Returns an opaque SYSTEM_TIMEOFDAY_INFORMATION structure.</summary> Private Const SYSTEM_TIMEINFORMATION As Integer = 3 ''' <summary>The value returned by NtQuerySystemInformation is no error occurred.</summary> Private Const NO_ERROR As Integer = 0 ''' <summary>Holds the old idle time.</summary> Private _oldIdleTime As Long ''' <summary>Holds the old system time.</summary> Private _oldSystemTime As Long ''' <summary>Holds the number of processors in the system.</summary> Private _processorCount As Double End ClassCpuUsageNt
1 Private NotInheritable Class MemUsage 2 <StructLayout(LayoutKind.Sequential)> 3 Private Structure MEMORY_INFO 4 ''' <summary> 5 ''' 当前结构体大小 6 ''' </summary> 7 Public dwLength As UInteger 8 ''' <summary> 9 ''' 当前内存使用率 10 ''' </summary> 11 Public dwMemoryLoad As UInteger 12 ''' <summary> 13 ''' 总计物理内存大小 14 ''' </summary> 15 Public dwTotalPhys As UInteger 16 ''' <summary> 17 ''' 可用物理内存大小 18 ''' </summary> 19 Public dwAvailPhys As UInteger 20 ''' <summary> 21 ''' 总计交换文件大小 22 ''' </summary> 23 Public dwTotalPageFile As UInteger 24 ''' <summary> 25 ''' 可用交换文件大小 26 ''' </summary> 27 Public dwAvailPageFile As UInteger 28 ''' <summary> 29 ''' 总计虚拟内存大小 30 ''' </summary> 31 Public dwTotalVirtual As UInteger 32 ''' <summary> 33 ''' 可用虚拟内存大小 34 ''' </summary> 35 Public dwAvailVirtual As UInteger 36 End Structure 37 <DllImport("kernel32")> 38 Private Shared Sub GlobalMemoryStatus(ByRef meminfo As MEMORY_INFO) 39 End Sub 40 41 Public Function Query() As Int32 42 Dim iRet As Int32 = 0 43 Try 44 Dim MemInfo As New MEMORY_INFO 45 GlobalMemoryStatus(MemInfo) 46 iRet = CInt(MemInfo.dwMemoryLoad) 47 Debug.Print("[DEBUG] GlobalMemoryStatus dwMemoryLoad={0}", iRet) 48 Catch ex As Exception 49 Debug.Print("[WARN ] GlobalMemoryStatus Err:{0}", ex.Message) 50 End Try 51 Return iRet 52 End Function 53 54 ''' <summary> 55 ''' 格式化容量大小 56 ''' </summary> 57 ''' <param name="size">容量(B)</param> 58 ''' <returns>已格式化的容量</returns> 59 Private Shared Function FormatSize(ByVal size As Double) As String 60 Dim d As Double = size 61 Dim i As Integer = 0 62 Do While (d > 1024) AndAlso (i < 5) 63 d /= 1024 64 i += 1 65 Loop 66 Dim unit() As String = {"B", "KB", "MB", "GB", "TB"} 67 Return (String.Format("{0} {1}", Math.Round(d, 2), unit(i))) 68 End Function 69 End ClassMemUsage
参考资料