WorkingSet64工作集(Working Set)進程實際使用的物理內存(含共享內存)。
VirtualMemorySize64 提交大小(Commit Size)進程占用的虛擬地址空間總量(含物理內存 + 頁面文件)。
PrivateMemorySize64 專用工作集(Private Working Set)進程獨占的物理內存(不含共享部分)。
代碼
/// <summary> /// 獲取進程cpu使用率 方式1 /// </summary> /// <param name="process"></param> /// <returns></returns> public static ProcessResult GetProcessCpuPerUsage(Process process) { ProcessResult result = new ProcessResult(); result.ProcessId = process.Id; result.ProcessName = process.ProcessName; result.MemoryUsage = Math.Round(Convert.ToDouble(process.PrivateMemorySize64 / 1024) / 1024, 1); //方式1 創建一個 PerformanceCounter 來獲取進程的CPU時間 try { //計算機CPU總核心數 int coreCount = Environment.ProcessorCount; result.CoresCount = coreCount; // 獲取當前頻率百分比 using (PerformanceCounter currentFreqPercentCounter = new PerformanceCounter( "Processor Information", "% of Maximum Frequency", "_Total" )) { currentFreqPercentCounter.NextValue(); //獲取基準頻率 float maxFreq = GetMaxFrequency(); result.MaxFreq = maxFreq; //獲取實時頻率(需通過百分比計算) float currentFreqPercent = currentFreqPercentCounter.NextValue(); result.CurrentFreqPercent = currentFreqPercent; //實際頻率 float currentFreq = maxFreq * (currentFreqPercent / 100); result.CurrentFreq = currentFreq; //公式:基準頻率 * 進程頁面cpu占用率 = 實際頻率 * 詳細信息cpu占用率 //創建進程 CPU 使用率計數器 using (PerformanceCounter cpuCounter = new PerformanceCounter("Process", "% Processor Time", process.ProcessName, true)) { // 設置讀取間隔 cpuCounter.NextValue(); // 等待1秒 Thread.Sleep(1000); // 獲取CPU使用率 當前值 = (當前計數值 - 起始計數值) / (當前時間 - 起始時間) double cpuUsage = Convert.ToDouble(cpuCounter.NextValue()); result.ProcessCpuUsageSum = cpuUsage; //占用核心數 = (進程CPU使用率 / 100) × 邏輯核心數 (經測試結果有時候會超過16核) int processOccupiedCores = Convert.ToInt32((cpuUsage / 100) * coreCount); result.ProcessOccupiedCores = processOccupiedCores; //除以核心數 得到平均 cpu使用率 double cpuUsageAvg = cpuUsage / coreCount; result.ProcessCpuUsageAvg = cpuUsage / coreCount; result.ProcessCpuUsageAvgOccupied = cpuUsage / processOccupiedCores; //基準頻率 * 進程頁面cpu占用率 = 實際頻率 * 詳細信息cpu占用率 //進程頁面cpu占用率 = (實際頻率 * 詳細信息cpu占用率)/基準頻率 //var proUse = currentFreq * cpuUsageAvg / maxFreq; result.ProcessCpuUsageAvgSpecial = (currentFreq * result.ProcessCpuUsageAvg) / maxFreq; result.ProcessCpuUsageAvgOccupiedSpecial = (currentFreq * result.ProcessCpuUsageAvgOccupied) / maxFreq; return result; } } } catch (Exception ex) { Console.WriteLine(process.ProcessName + "獲取cpu占用率異常:" + ex.Message); } return result; } /// <summary> /// 獲取進程cpu使用率 方式2 /// </summary> /// <param name="process"></param> /// <returns></returns> public static ProcessResult GetProcessCpuPerUsage2(Process process) { ProcessResult result = new ProcessResult(); result.ProcessId = process.Id; result.ProcessName = process.ProcessName; result.MemoryUsage = Math.Round(Convert.ToDouble(process.PrivateMemorySize64 / 1024) / 1024, 1); try { //CPU總核心數 int coreCount = Environment.ProcessorCount; //偵測開始時間 DateTime startTime = DateTime.Now; //進程在所有CPU核心上實際消耗的總時間 TimeSpan startCpuTime = process.TotalProcessorTime; // 等待一段時間 Thread.Sleep(1000); //進程在所有CPU核心上實際消耗的總時間 TimeSpan endCpuTime = process.TotalProcessorTime; //CPU總消耗時間 TimeSpan cpuUsed = endCpuTime - startCpuTime; //偵測結束時間 DateTime endTime = DateTime.Now; //偵測消耗時間 double checkTotalMilliseconds = (endTime - startTime).TotalSeconds * 1000.0; //CPU在單個核心上的使用率 = CPU總消耗時間 除以 偵測消耗時間 乘以 100 double cpuUsageSingleCore = (cpuUsed.TotalMilliseconds / checkTotalMilliseconds) * 100; //CPU在所有核心上的平均使用率 = CPU總消耗時間 除以 核心數后,得到平均每個核心消耗的時間,然后再除以 偵測消耗時間 乘以 100 double cpuUsageMultiCore = (cpuUsed.TotalMilliseconds / coreCount / checkTotalMilliseconds) * 100; //保留一位小數 result.ProcessCpuUsageAvg = Math.Round(cpuUsageMultiCore, 1); return result; } catch (Exception ex) { Console.WriteLine(process.ProcessName + "獲取cpu占用率異常:" + ex.Message); } return result; }
在 C# 中獲取資源監視器中 ??“專用(KB)”? 列的值(即進程的 ?私有工作集內存),需通過 ?Performance Counters(性能計數器)? 監控 Process 類別的 ?Working Set - Private 計數器。
以下是具體實現方法和代碼示例:
核心原理:
cmd命令resmon打開資源監視器。資源監視器的“專用(KB)”列:表示進程獨占的物理內存(即不與其他進程共享的部分),對應 Windows 性能計數器中的 ?Working Set - Private。?
與 Process.PrivateMemorySize64 的區別:
PrivateMemorySize64:統計進程的私有虛擬內存(包含頁面文件提交量)。私有虛擬內存提交量,對應資源監視器 提交(KB)
Working Set - Private:統計進程獨占的物理內存(與資源監視器一致)。私有物理內存(專用),對應資源監視器 專用(KB)
關鍵步驟解釋
(1) 獲取進程實例名稱
?問題:PerformanceCounter 需通過進程實例名稱(如 chrome#1)定位具體進程。同一個程序可能會多開,出現多個實例問題。
?解決:通過 ID Process 計數器匹配進程 ID 和實例名稱。?
(2) 讀取 "Working Set - Private" 計數器
注意:首次調用 NextValue() 返回 0,需等待后再次調用。?
單位:計數器返回的字節數,需轉換為 KB。
(3) 權限要求
需以管理員身份運行程序,否則可能無法訪問其他進程的計數器。
通過性能計數器,可以準確獲取資源監視器中 ??“專用(KB)”? 列的值。如果目標是監控系統級內存,可使用 GlobalMemoryStatusEx API 獲取全局內存狀態。
實現代碼:
/// <summary> /// 獲取所有進程實例名稱 /// </summary> /// <returns></returns> public static List<string> GetAllInstanceNames() { PerformanceCounterCategory category = new PerformanceCounterCategory("Process"); string[] instanceNames = category.GetInstanceNames(); return instanceNames.ToList(); } /// <summary> /// 獲取當前進程ID的實例名稱 /// 根據進程ID和實例名集合獲取進程ID對應的實例名稱 /// </summary> /// <param name="processId"></param> /// <param name="instanceNames"></param> /// <returns></returns> public static string GetProcessInstanceName(int processId, List<string> instanceNames) { foreach (string instanceName in instanceNames) { using (PerformanceCounter pidCounter = new PerformanceCounter( "Process", "ID Process", instanceName, true)) { if ((int)pidCounter.NextValue() == processId) return instanceName; } } return null; } /// <summary> /// 獲取進程工作集中的私有內存占用量(Working Set - Private) /// Working Set - Private /// </summary> /// <param name="process"></param> /// <returns></returns> public static double GetProcessMemoryPrivateWorkingSetUsage(Process process, List<string> instanceNames) { try { //獲取當前進程ID的實例名稱 var instanceName = GetProcessInstanceName(process.Id, instanceNames); if (string.IsNullOrEmpty(instanceName)) { Console.WriteLine("獲取進程工作集中的私有內存占用量異常:無法獲取當前進程ID的實例名稱。"); return 0; } //獲取當前進程實例名稱的工作集中的私有內存占用量(Working Set - Private) using (PerformanceCounter virtualBytesCounter = new PerformanceCounter( "Process", "Working Set - Private", instanceName, true)) { virtualBytesCounter.NextValue(); Thread.Sleep(100); long commitSize = (long)virtualBytesCounter.NextValue(); double result = Math.Round(Convert.ToDouble(commitSize) / 1024 / 1024, 1); return result; } } catch (Exception ex) { Console.WriteLine("獲取進程工作集中的私有內存占用量異常:" + ex.Message); } return 0; }
通過PROCESS_MEMORY_COUNTERS_EX結構體調用Windows API獲取內存量
using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace XCGConsoleApp { /// <summary> /// 使用 PROCESS_MEMORY_COUNTERS_EX 結構體 /// Windows API 的 GetProcessMemoryInfo 函數返回的 PROCESS_MEMORY_COUNTERS_EX 結構體中, /// PagefileUsage 字段表示進程的 ?分頁內存提交量?(即分配給頁面文件的內存)。 /// ?關鍵點 /// ** PagefileUsage:直接對應進程的 ?分頁內存提交量**?(即分配給頁面文件的內存)。 /// 權限要求:需進程具有 PROCESS_QUERY_INFORMATION 或 PROCESS_QUERY_LIMITED_INFORMATION 權限。 /// </summary> public class PagedMemoryFetcher { [DllImport("psapi.dll", SetLastError = true)] private static extern bool GetProcessMemoryInfo( IntPtr processHandle, out PROCESS_MEMORY_COUNTERS_EX counters, uint size ); [StructLayout(LayoutKind.Sequential)] private struct PROCESS_MEMORY_COUNTERS_EX { public uint cbSize;// 結構體的大小,以字節為單位。 public uint PageFaultCount;//缺頁異常數 public long WorkingSetSize;//當前工作集的大小,以字節為單位。 public long QuotaPeakPagedPoolUsage; public long QuotaPagedPoolUsage; public long QuotaPeakNonPagedPoolUsage; public long QuotaNonPagedPoolUsage; public long PagefileUsage;//分頁文件的使用量,以字節為單位。 public long PeakPagefileUsage;//分頁文件使用的峰值,以字節為單位? public ulong PeakWorkingSetSize;//工作集的峰值大小,以字節為單位。 public ulong PrivateUsage;//提交大小,資源監視器 提交(KB) } public static long GetPagedMemoryUsage(Process process) { IntPtr handle = process.Handle; PROCESS_MEMORY_COUNTERS_EX counters; bool success = GetProcessMemoryInfo( handle, out counters, //(uint)Marshal.SizeOf(typeof(PROCESS_MEMORY_COUNTERS_EX)) (uint)Int32.MaxValue ); if (!success) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); return (long)counters.WorkingSetSize; } /** public static void Main() { Process currentProcess = Process.GetCurrentProcess(); long pagedMemory = GetPagedMemoryUsage(currentProcess); Console.WriteLine($"分頁內存提交量: {pagedMemory / 1024 / 1024:N2} MB"); } */ } }
浙公網安備 33010602011771號