最准确高效的方式是调用Process.GetCurrentProcess().WorkingSet64,它返回进程当前实际占用的物理内存字节数,与任务管理器“内存(专用工作集)”一致,开销低、无需权限、跨.NET版本兼容。

直接读 Process.GetCurrentProcess().WorkingSet64 就能拿到当前程序真实占用的物理内存字节数,这是最准、最快、最省事的做法;别碰 GC.GetTotalMemory(false),它和系统内存完全无关。
用 WorkingSet64 获取当前进程内存占用(任务管理器对齐)
这个值对应任务管理器里“内存(专用工作集)”列,是操作系统当前为该进程钉在物理内存里的实际字节数,含共享页但不含未访问的提交页。
- 调用开销极低,每秒几百次没问题
- 不需要管理员权限,.NET Framework 4.0+ 和 .NET Core 3.0+ 都支持
- 别用
PrivateMemorySize64:它包含已提交但从未访问的页,空闲时虚高 - 别用
VirtualMemorySize64:那是虚拟地址空间大小,和物理内存占用毫无关系 - Linux/macOS 下
PeakWorkingSet64不可用——返回 0 或乱值,Windows 才准
为什么 GC.GetTotalMemory(false) 不能当内存占用看
它只返回托管堆中已分配对象的总字节数,不包括非托管资源(如 Bitmap、文件映射、P/Invoke 分配内存)、线程栈、JIT 代码、CLR 内部结构等。
- 一个加载了 500MB 图片的程序,
GC.GetTotalMemory(false)可能只报 20MB -
GC.GetTotalMemory(true)会强制 GC,生产环境禁用 - 它反映的是“托管堆膨胀”,不是“会不会被系统杀掉”
PerformanceCounter 获取系统内存使用率(需计算)
Windows 性能计数器不提供现成的“内存使用率”,必须自己算:(TotalPhysicalMemory − Available MBytes) / TotalPhysicalMemory。
- 用
PerformanceCounter("Memory", "Available MBytes")读空闲内存(单位 MB,固定) - 总内存别用
GC.GetTotalMemory,推荐new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory(轻量、准确、无需权限) - 避免用
"% Committed Bytes In Use":那是虚拟内存提交比例,和用户感知的“内存吃满”不一致 - 计数器对象要复用,别每秒 new 一个——句柄泄漏风险高
获取当前进程 CPU 使用率(注意实例名和间隔)
用 PerformanceCounter("Process", "% Processor Time", processName),但要注意它的值是“占全系统 CPU 时间的百分比”,不是“用了几个核”。
- 实例名必须是进程名(如
"devenv"或"MyApp"),不是 PID - 首次
NextValue()必须丢弃,第二次才有效;两次调用至少间隔 1000ms,低于 800ms 值就不可信 - 单线程满载时,该值峰值 ≈ 100% ÷ 逻辑处理器数量(比如 16 核机器上最多约 6.25%)
- 别写成
"process"(小写)或"Process"(拼错类别名),Windows 计数器名严格区分大小写
真正容易被忽略的是:CPU 和内存采样机制完全不同——前者必须差分+延时,后者是瞬时读取;混用逻辑会导致 CPU 恒为 0 或内存数值飘忽。另外,所有 PerformanceCounter 实例记得 Dispose(),尤其在长周期监控中。


















