C#获取已使用内存的百分比

51

我创建了一个性能计数器,可以检查内存总使用量(%),但问题是它给出的值与任务管理器不同。例如:我的程序显示34%,而任务管理器显示40%。

有什么想法吗?

注意:
我尝试获取系统可用RAM,而不是进程使用的RAM。

当前代码

private PerformanceCounter performanceCounterRAM = new PerformanceCounter();

performanceCounterRAM.CounterName = "% Committed Bytes In Use";
performanceCounterRAM.CategoryName = "Memory";

progressBarRAM.Value = (int)(performanceCounterRAM.NextValue());
            labelRAM.Text = "RAM: " + progressBarRAM.Value.ToString(CultureInfo.InvariantCulture) + "%";

编辑
我使用计时器每秒刷新进度条和标签。


与任务管理器相比,你的值和TM是否仅取决于时间延迟?我的意思是,任务管理器也会每秒刷新其值。因此,如果您的应用程序和任务管理器具有同步的刷新时间,那么它们是否会有相同的值呢? - Jens H
我也尝试过这个,但程序仍然显示比TM低的值:(。 - Yuki Kutsuya
正在使用哪个操作系统?XP,Win 7,Vista? - mkus
4个回答

68
你可以使用GetPerformanceInfo Windows API,它会显示与Windows 7任务管理器完全相同的值。这里是一个控制台应用程序,它获取可用物理内存,您可以轻松获得其他GetPerformanceInfo返回的信息,请参考MSDN PERFORMANCE_INFORMATION 结构文档以查看如何计算MiB中的值,基本上所有SIZE_T值都以页面为单位,因此必须乘以PageSize。
更新:我更新了此代码以显示百分比,这不是最优解,因为它调用了两次GetPerformanceInfo,但我希望您能理解这个想法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplicationPlayground
{
  class Program
  {
    static void Main(string[] args)
    {
      while (true)
      {
        Int64 phav = PerformanceInfo.GetPhysicalAvailableMemoryInMiB();
        Int64 tot = PerformanceInfo.GetTotalMemoryInMiB();
        decimal percentFree = ((decimal)phav / (decimal)tot) * 100;
        decimal percentOccupied = 100 - percentFree;
        Console.WriteLine("Available Physical Memory (MiB) " + phav.ToString());
        Console.WriteLine("Total Memory (MiB) " + tot.ToString());
        Console.WriteLine("Free (%) " + percentFree.ToString());
        Console.WriteLine("Occupied (%) " + percentOccupied.ToString());
        Console.ReadLine();
      }
    }
  }

  public static class PerformanceInfo
  {
    [DllImport("psapi.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetPerformanceInfo([Out] out PerformanceInformation PerformanceInformation, [In] int Size);

    [StructLayout(LayoutKind.Sequential)]
    public struct PerformanceInformation
    {
      public int Size;
      public IntPtr CommitTotal;
      public IntPtr CommitLimit;
      public IntPtr CommitPeak;
      public IntPtr PhysicalTotal;
      public IntPtr PhysicalAvailable;
      public IntPtr SystemCache;
      public IntPtr KernelTotal;
      public IntPtr KernelPaged;
      public IntPtr KernelNonPaged;
      public IntPtr PageSize;
      public int HandlesCount;
      public int ProcessCount;
      public int ThreadCount;
    }

    public static Int64 GetPhysicalAvailableMemoryInMiB()
    {
        PerformanceInformation pi = new PerformanceInformation();
        if (GetPerformanceInfo(out pi, Marshal.SizeOf(pi)))
        {
          return Convert.ToInt64((pi.PhysicalAvailable.ToInt64() * pi.PageSize.ToInt64() / 1048576));
        }
        else
        {
          return -1;
        }

    }

    public static Int64 GetTotalMemoryInMiB()
    {
      PerformanceInformation pi = new PerformanceInformation();
      if (GetPerformanceInfo(out pi, Marshal.SizeOf(pi)))
      {
        return Convert.ToInt64((pi.PhysicalTotal.ToInt64() * pi.PageSize.ToInt64() / 1048576));
      }
      else
      {
        return -1;
      }

    }
  }
}

这似乎显示了可用内存的数量,很好!但是我怎么才能得到百分比呢?我的意思是,我需要除以哪些值等等? - Yuki Kutsuya
2
我整理了一个小类,现在使用起来更加方便了,这是它的链接http://www.antoniob.com/windows-psapi-getperformanceinfo-csharp-wrapper.html - Antonio Bakula
为什么你必须将可用物理内存和总物理内存乘以页面文件大小?如果我不这样做,我得到的数字就像“7”和“2”一样没有意义,但我觉得我想要实际的内存大小而不包括页面文件。 - Daniel
也许我没有理解你的意思,但是你必须乘以页面大小,因为GetPerformanceInfo方法返回的值是以页面为单位的。 - Antonio Bakula

16

性能计数器不是一个好主意。 使用此代码从任务管理器获取内存使用率的百分比

var wmiObject = new ManagementObjectSearcher("select * from Win32_OperatingSystem");

var memoryValues = wmiObject.Get().Cast<ManagementObject>().Select(mo => new {
    FreePhysicalMemory = Double.Parse(mo["FreePhysicalMemory"].ToString()),
    TotalVisibleMemorySize = Double.Parse(mo["TotalVisibleMemorySize"].ToString())
}).FirstOrDefault();

if (memoryValues != null) {
    var percent = ((memoryValues.TotalVisibleMemorySize - memoryValues.FreePhysicalMemory) / memoryValues.TotalVisibleMemorySize) * 100;
}

1
谢谢,这个有效。但你能用同样的方法来获取CPU使用率百分比吗? - Jesper
请参考 https://dev59.com/n2kw5IYBdhLWcg3wmruH#9778276 获取通过 ManagementObjectSearcher 获取 CPU 使用率的示例。 - Tyler Forsythe
6
你能解释一下为什么性能计数器不是一个好主意吗? - Stealth Rabbi

8

我认为任务管理器报告的物理内存百分比实际上是与您的PerformanceCounter使用的“% Committed Bytes In Use”不同的指标。

在我的计算机上,在性能监视器中查看这些值时,存在明显的20%差异:

enter image description here

这篇文章表明,% Committed Bytes指标考虑了页面文件的大小,而不仅仅是机器的物理内存。这可以解释为什么此值始终低于任务管理器的值。

您可能会更幸运地使用Memory \ Available Bytes指标计算百分比,但我不确定如何从PerformanceCounter获取总物理内存量。


1
你可以在性能监视器底部使用“显示描述”。点击此处查看 %已提交的字节使用率是Memory\Committed Bytes与Memory\Commit Limit的比率。已提交的内存是实际内存,如果需要写入磁盘,则已在分页文件中保留了空间。承诺限制由分页文件的大小确定。如果扩大分页文件,则承诺限制增加,比率减小)。此计数器仅显示当前百分比值;它不是平均值。
所以,是的,性能监视器使用分页文件,而任务管理器使用实际RAM。

2
请在您的帖子中添加引用来源。 - nietonfir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接