在C#开发中,监控进程的资源使用情况是很多场景下的常见需求,比如性能优化、资源告警、进程状态检测等,而Process类作为.NET框架中用于操作本地和远程进程的核心类,提供了丰富的进程信息属性,能够直接获取内存占用相关数据,也可以通过简单的计算实现CPU使用率的统计。

Process类基础介绍
Process类位于System.Diagnostics命名空间下,使用时需要先添加对应的命名空间引用。它提供了静态方法和实例方法两种使用方式,静态方法可以直接获取本地计算机的进程列表,实例方法则用于操作单个指定进程。要获取进程的内存和CPU信息,我们主要使用实例属性以及简单的计算逻辑。
using System.Diagnostics; // 获取当前正在运行的程序的进程实例 Process currentProcess = Process.GetCurrentProcess();
获取程序内存占用的方法
Process类提供了多个和内存相关的属性,不同属性对应不同的内存统计维度,开发者可以根据实际需求选择合适的属性:
- WorkingSet64:获取进程的工作集大小,也就是进程当前在物理内存中占用的字节数,包含共享内存部分,是最常用的物理内存统计指标。
- PrivateMemorySize64:获取进程的专用内存大小,也就是该进程独占的物理内存字节数,不包含共享内存部分。
- VirtualMemorySize64:获取进程的虚拟内存大小,也就是进程占用的虚拟地址空间字节数。
- PagedMemorySize64:获取进程的分页内存大小,也就是可以写入到虚拟内存分页文件的内存字节数。
下面是一个获取当前程序内存占用的完整示例,将字节数转换为更易读的MB单位:
using System;
using System.Diagnostics;
class MemoryMonitor
{
static void Main()
{
// 获取当前进程实例
Process process = Process.GetCurrentProcess();
// 获取工作集内存(物理内存占用),单位字节
long workingSet = process.WorkingSet64;
// 转换为MB,1MB = 1024 * 1024 字节
double workingSetMB = workingSet / (1024.0 * 1024.0);
// 获取专用内存大小
long privateMemory = process.PrivateMemorySize64;
double privateMemoryMB = privateMemory / (1024.0 * 1024.0);
Console.WriteLine($"当前程序物理内存占用(工作集):{workingSetMB:F2} MB");
Console.WriteLine($"当前程序专用内存占用:{privateMemoryMB:F2} MB");
}
}
使用Process类查看CPU使用率
Process类没有直接提供CPU使用率的属性,需要通过TotalProcessorTime属性结合时间间隔计算实现。TotalProcessorTime表示进程启动以来占用的CPU总时间,我们通过两次采样的时间差和两次采样的CPU总时间差,就能计算出这段时间内的CPU使用率。
计算逻辑如下:
- 第一次采样:记录当前时间戳t1,记录进程的TotalProcessorTime值cpu1。
- 等待一个固定的时间间隔(比如1秒)。
- 第二次采样:记录当前时间戳t2,记录进程的TotalProcessorTime值cpu2。
- CPU使用率 = (cpu2 - cpu1) / (t2 - t1) / 处理器核心数 * 100%。
下面是完整的CPU使用率计算示例:
using System;
using System.Diagnostics;
class CpuMonitor
{
static void Main()
{
Process process = Process.GetCurrentProcess();
// 获取处理器核心数
int processorCount = Environment.ProcessorCount;
// 第一次采样
TimeSpan cpuTime1 = process.TotalProcessorTime;
DateTime time1 = DateTime.Now;
// 等待1秒
System.Threading.Thread.Sleep(1000);
// 第二次采样,需要重新获取进程实例的最新数据
process.Refresh();
TimeSpan cpuTime2 = process.TotalProcessorTime;
DateTime time2 = DateTime.Now;
// 计算时间差,转换为秒
double timeDiff = (time2 - time1).TotalSeconds;
// 计算CPU时间差,转换为秒
double cpuDiff = (cpuTime2 - cpuTime1).TotalSeconds;
// 计算CPU使用率
double cpuUsage = cpuDiff / timeDiff / processorCount * 100;
Console.WriteLine($"当前程序CPU使用率:{cpuUsage:F2}%");
}
}
监控指定进程的资源使用情况
除了监控当前程序,我们还可以通过Process类获取其他指定进程的资源信息,只需要通过进程ID或者进程名称获取对应的Process实例即可。
通过进程名称获取所有同名进程的示例:
using System;
using System.Diagnostics;
using System.Linq;
class SpecifiedProcessMonitor
{
static void Main()
{
// 获取所有名为notepad的进程(记事本进程)
Process[] processes = Process.GetProcessesByName("notepad");
if (processes.Length == 0)
{
Console.WriteLine("未找到记事本进程");
return;
}
// 取第一个记事本进程
Process targetProcess = processes[0];
Console.WriteLine($"进程名称:{targetProcess.ProcessName},进程ID:{targetProcess.Id}");
Console.WriteLine($"内存占用:{targetProcess.WorkingSet64 / (1024.0 * 1024.0):F2} MB");
}
}
注意事项
- 获取进程信息需要对应的系统权限,如果监控其他用户的进程或者系统进程,可能会因为权限不足抛出异常,需要做好异常处理。
- 计算CPU使用率时,调用
Refresh()方法可以更新Process实例的属性值,避免获取到旧数据。 - WorkingSet64等内存属性返回的是字节数,实际使用时建议根据需求转换为KB、MB或者GB单位,提升可读性。
- 如果进程已经退出,再访问其属性会抛出
InvalidOperationException异常,需要在访问前判断进程是否还在运行,或者添加异常捕获逻辑。
Process类的相关属性都是实时从系统获取的,频繁获取可能会对性能有轻微影响,如果是高频监控场景,建议合理设置采样间隔,避免过于频繁调用。