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号