51

I've created a performancecounter that can check the total memory usage in %, but the problem is that it doesn't give me the same value as in task manager shows me. for example: my program says 34% but task manager says 40%.

Any ideas?

NOTE
I try to get the available RAM of the system, not the used RAM by a process.

Current Code

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) + "%";

EDIT
I refresh the progressbar and the label every second with a timer.

easwee
  • 15,757
  • 24
  • 60
  • 83
Yuki Kutsuya
  • 3,968
  • 11
  • 46
  • 63
  • Compared to the Task Manager, is it possible that the TM and your value just depend on the time delay? I mean, the TM refreshes its value every second, too. So If your application and the Task Manger have a synchronized refresh-timing, do they *then* have the same value? – Jens H Apr 05 '12 at 11:16
  • I've tried this also, but the program still shows a lower value than the TM :(. – Yuki Kutsuya Apr 05 '12 at 11:19
  • Which OS is being used? XP, Win 7, Vista ? – mkus Apr 05 '12 at 12:04

4 Answers4

68

You could use GetPerformanceInfo windows API, it shows exactly the same values as Windows Task Manager on Windows 7, here is the console application that get's available physical memory, you could easily get other information that GetPerformanceInfo returns, consult MSDN PERFORMANCE_INFORMATION structure documentation to see how to calculate value in MiB, basically all SIZE_T values are in pages, so you must multiply it with PageSize.

Update: I updated this code to show percentage, it's not optimal because it's calling GetPerformanceInfo two times, but I hope that you get the idea.

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;
      }

    }
  }
}
Antonio Bakula
  • 20,445
  • 6
  • 75
  • 102
  • This seems to display the free amount of memory, which is nice! But how can i get the percentage? I mean, which values do I need to divide etc? – Yuki Kutsuya Apr 05 '12 at 13:31
  • 2
    I put together little class and it's easier to use it now, here it is http://www.antoniob.com/windows-psapi-getperformanceinfo-csharp-wrapper.html – Antonio Bakula May 08 '12 at 09:28
  • Why is it that you have to multiply the physical available and physical total by the page file size? When I don't, I get numbers that don't make sense like "7" and "2", but I feel like I would want the actual memory size without the page file included. – Daniel Feb 26 '19 at 17:31
  • Maybe I didn't understand you correctly but you have to multiply by page size simply because GetPerformanceInfo method returns values in pages. – Antonio Bakula Feb 26 '19 at 20:38
16

Performance counters is not good idea. Use this code to get % of memory usage from Task Manager

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;
}
ZOXEXIVO
  • 920
  • 9
  • 21
8

I think the Physical memory percentage reported by Task Manager is actually a different metric to the % Committed Bytes In Use your PerformanceCounter is using.

On my machine there's a clear 20% difference between these values when viewed in the performance monitor:

enter image description here

This article indicates that the % Committed Bytes metric takes the size of the pagefile into account, not just the machine's physical memory. This would explain why this value is consistently lower than Task Manager's value.

You may have better luck calculating a percentage using the Memory \ Available Bytes metric, but I'm not sure how to get the total amount of physical memory from PerformanceCounter.

raveturned
  • 2,637
  • 24
  • 30
1

You can use "show description" on the bottom of Performance monitor. To quote

% Committed Bytes In Use is the ratio of Memory\Committed Bytes to the Memory\Commit Limit. Committed memory is the physical memory in use for which space has been reserved in the paging file should it need to be written to disk. The commit limit is determined by the size of the paging file. If the paging file is enlarged, the commit limit increases, and the ratio is reduced). This counter displays the current percentage value only; it is not an average.

Soo yes PM uses the paging file, while TM uses actual RAM.

Leigh
  • 28,765
  • 10
  • 55
  • 103