Process内存占用量:
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");
         }
         */
    }
}

 

posted on 2025-04-21 13:48  邢帅杰  阅读(746)  评论(0)    收藏  举报