如何得到计算机内存的总量?

使用 C # ,我想得到我的计算机所拥有的内存总量。 使用 PerformanceCounter,我可以通过设置:

counter.CategoryName = "Memory";
counter.Countername = "Available MBytes";

但我似乎找不到一种方法来获取总的记忆量。我该怎么做呢?

更新:

MagicKat: I saw that when I was searching, but it doesn't work - "Are you missing an assembly or reference?". I've looked to add that to the References, but I don't see it there.

154509 次浏览

.NET has a memory amount limit that it can access. In Windows XP 2GB was the "hard ceiling". For instance: You could have 4 GB in it, and it would kill the app when it hit 2GB.

Also in 64 bit mode, there is a percentage of memory you can use out of the system, so I'm not sure if you can ask for the whole thing or if this is specifically guarded against.

Add a reference to Microsoft.VisualBasic and a using Microsoft.VisualBasic.Devices;.

The ComputerInfo class has all the information that you need.

You could use 'WMI'.

I found a 'snippet'.

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
Set colComputer = objWMIService.ExecQuery _
("Select * from Win32_ComputerSystem")


For Each objComputer in colComputer
strMemory = objComputer.TotalPhysicalMemory
Next

The Windows API function GlobalMemoryStatusEx can be called with p/invoke:

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(NativeMethods.MEMORYSTATUSEX));
}
}




[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);

Then use like:

ulong installedMemory;
MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX();
if( GlobalMemoryStatusEx( memStatus))
{
installedMemory = memStatus.ullTotalPhys;
}

Or you can use WMI (managed but slower) to query TotalPhysicalMemory in the Win32_ComputerSystem class.

Add a reference to Microsoft.VisualBasic.dll, as someone mentioned above. Then getting total physical memory is as simple as this (yes, I tested it):

static ulong GetTotalMemoryInBytes()
{
return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory;
}

If you happen to be using Mono, then you might be interested to know that Mono 2.8 (to be released later this year) will have a performance counter which reports the physical memory size on all the platforms Mono runs on (including Windows). You would retrieve the value of the counter using this code snippet:

using System;
using System.Diagnostics;


class app
{
static void Main ()
{
var pc = new PerformanceCounter ("Mono Memory", "Total Physical Memory");
Console.WriteLine ("Physical RAM (bytes): {0}", pc.RawValue);
}
}

If you are interested in C code which provides the performance counter, it can be found here.

/*The simplest way to get/display total physical memory in VB.net (Tested)


public sub get_total_physical_mem()


dim total_physical_memory as integer


total_physical_memory=CInt((My.Computer.Info.TotalPhysicalMemory) / (1024 * 1024))
MsgBox("Total Physical Memory" + CInt((My.Computer.Info.TotalPhysicalMemory) / (1024 * 1024)).ToString + "Mb" )
end sub
*/




//The simplest way to get/display total physical memory in C# (converted Form http://www.developerfusion.com/tools/convert/vb-to-csharp)


public void get_total_physical_mem()
{
int total_physical_memory = 0;


total_physical_memory = Convert.ToInt32((My.Computer.Info.TotalPhysicalMemory) /  (1024 * 1024));
Interaction.MsgBox("Total Physical Memory" + Convert.ToInt32((My.Computer.Info.TotalPhysicalMemory) / (1024 * 1024)).ToString() + "Mb");
}

you can simply use this code to get those information, just add the reference

using Microsoft.VisualBasic.Devices;

and the simply use the following code

    private void button1_Click(object sender, EventArgs e)
{
getAvailableRAM();
}


public void getAvailableRAM()
{
ComputerInfo CI = new ComputerInfo();
ulong mem = ulong.Parse(CI.TotalPhysicalMemory.ToString());
richTextBox1.Text = (mem / (1024*1024) + " MB").ToString();
}

Another way to do this, is by using the .NET System.Management querying facilities:

string Query = "SELECT Capacity FROM Win32_PhysicalMemory";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(Query);


UInt64 Capacity = 0;
foreach (ManagementObject WniPART in searcher.Get())
{
Capacity += Convert.ToUInt64(WniPART.Properties["Capacity"].Value);
}


return Capacity;

Nobody has mentioned GetPerformanceInfo yet. PInvoke signatures are available.

This function makes the following system-wide information available:

  • CommitTotal
  • CommitLimit
  • CommitPeak
  • PhysicalTotal
  • PhysicalAvailable
  • SystemCache
  • KernelTotal
  • KernelPaged
  • KernelNonpaged
  • PageSize
  • HandleCount
  • ProcessCount
  • ThreadCount

PhysicalTotal is what the OP is looking for, although the value is the number of pages, so to convert to bytes, multiply by the PageSize value returned.

This function (ManagementQuery) works on Windows XP and later:

private static string ManagementQuery(string query, string parameter, string scope = null) {
string result = string.Empty;
var searcher = string.IsNullOrEmpty(scope) ? new ManagementObjectSearcher(query) : new ManagementObjectSearcher(scope, query);
foreach (var os in searcher.Get()) {
try {
result = os[parameter].ToString();
}
catch {
//ignore
}


if (!string.IsNullOrEmpty(result)) {
break;
}
}


return result;
}

Usage:

Console.WriteLine(BytesToMb(Convert.ToInt64(ManagementQuery("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem", "TotalPhysicalMemory", "root\\CIMV2"))));

All the answers here, including the accepted one, will give you the total amount of RAM available for use. And that may have been what OP wanted.

But if you are interested in getting the amount of installed RAM, then you'll want to make a call to the GetPhysicallyInstalledSystemMemory function.

From the link, in the Remarks section:

The GetPhysicallyInstalledSystemMemory function retrieves the amount of physically installed RAM from the computer's SMBIOS firmware tables. This can differ from the amount reported by the GlobalMemoryStatusEx function, which sets the ullTotalPhys member of the MEMORYSTATUSEX structure to the amount of physical memory that is available for the operating system to use. The amount of memory available to the operating system can be less than the amount of memory physically installed in the computer because the BIOS and some drivers may reserve memory as I/O regions for memory-mapped devices, making the memory unavailable to the operating system and applications.

Sample code:

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetPhysicallyInstalledSystemMemory(out long TotalMemoryInKilobytes);


static void Main()
{
long memKb;
GetPhysicallyInstalledSystemMemory(out memKb);
Console.WriteLine((memKb / 1024 / 1024) + " GB of RAM installed.");
}
// use `/ 1048576` to get ram in MB
// and `/ (1048576 * 1024)` or `/ 1048576 / 1024` to get ram in GB
private static String getRAMsize()
{
ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject item in moc)
{
return Convert.ToString(Math.Round(Convert.ToDouble(item.Properties["TotalPhysicalMemory"].Value) / 1048576, 0)) + " MB";
}


return "RAMsize";
}

Compatible with .Net and Mono (tested with Win10/FreeBSD/CentOS)

Using ComputerInfo source code and PerformanceCounters for Mono and as backup for .Net:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;


public class SystemMemoryInfo
{
private readonly PerformanceCounter _monoAvailableMemoryCounter;
private readonly PerformanceCounter _monoTotalMemoryCounter;
private readonly PerformanceCounter _netAvailableMemoryCounter;


private ulong _availablePhysicalMemory;
private ulong _totalPhysicalMemory;


public SystemMemoryInfo()
{
try
{
if (PerformanceCounterCategory.Exists("Mono Memory"))
{
_monoAvailableMemoryCounter = new PerformanceCounter("Mono Memory", "Available Physical Memory");
_monoTotalMemoryCounter = new PerformanceCounter("Mono Memory", "Total Physical Memory");
}
else if (PerformanceCounterCategory.Exists("Memory"))
{
_netAvailableMemoryCounter = new PerformanceCounter("Memory", "Available Bytes");
}
}
catch
{
// ignored
}
}


public ulong AvailablePhysicalMemory
{
[SecurityCritical]
get
{
Refresh();


return _availablePhysicalMemory;
}
}


public ulong TotalPhysicalMemory
{
[SecurityCritical]
get
{
Refresh();


return _totalPhysicalMemory;
}
}


[SecurityCritical]
[DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern void GlobalMemoryStatus(ref MEMORYSTATUS lpBuffer);


[SecurityCritical]
[DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);


[SecurityCritical]
private void Refresh()
{
try
{
if (_monoTotalMemoryCounter != null && _monoAvailableMemoryCounter != null)
{
_totalPhysicalMemory = (ulong) _monoTotalMemoryCounter.NextValue();
_availablePhysicalMemory = (ulong) _monoAvailableMemoryCounter.NextValue();
}
else if (Environment.OSVersion.Version.Major < 5)
{
var memoryStatus = MEMORYSTATUS.Init();
GlobalMemoryStatus(ref memoryStatus);


if (memoryStatus.dwTotalPhys > 0)
{
_availablePhysicalMemory = memoryStatus.dwAvailPhys;
_totalPhysicalMemory = memoryStatus.dwTotalPhys;
}
else if (_netAvailableMemoryCounter != null)
{
_availablePhysicalMemory = (ulong) _netAvailableMemoryCounter.NextValue();
}
}
else
{
var memoryStatusEx = MEMORYSTATUSEX.Init();


if (GlobalMemoryStatusEx(ref memoryStatusEx))
{
_availablePhysicalMemory = memoryStatusEx.ullAvailPhys;
_totalPhysicalMemory = memoryStatusEx.ullTotalPhys;
}
else if (_netAvailableMemoryCounter != null)
{
_availablePhysicalMemory = (ulong) _netAvailableMemoryCounter.NextValue();
}
}
}
catch
{
// ignored
}
}


private struct MEMORYSTATUS
{
private uint dwLength;
internal uint dwMemoryLoad;
internal uint dwTotalPhys;
internal uint dwAvailPhys;
internal uint dwTotalPageFile;
internal uint dwAvailPageFile;
internal uint dwTotalVirtual;
internal uint dwAvailVirtual;


public static MEMORYSTATUS Init()
{
return new MEMORYSTATUS
{
dwLength = checked((uint) Marshal.SizeOf(typeof(MEMORYSTATUS)))
};
}
}


private struct MEMORYSTATUSEX
{
private uint dwLength;
internal uint dwMemoryLoad;
internal ulong ullTotalPhys;
internal ulong ullAvailPhys;
internal ulong ullTotalPageFile;
internal ulong ullAvailPageFile;
internal ulong ullTotalVirtual;
internal ulong ullAvailVirtual;
internal ulong ullAvailExtendedVirtual;


public static MEMORYSTATUSEX Init()
{
return new MEMORYSTATUSEX
{
dwLength = checked((uint) Marshal.SizeOf(typeof(MEMORYSTATUSEX)))
};
}
}
}

For those who are using .net Core 3.0 there is no need to use PInvoke platform in order to get the available physical memory. The GC class has added a new method GC.GetGCMemoryInfo that returns a GCMemoryInfo Struct with TotalAvailableMemoryBytes as a property. This property returns the total available memory for the garbage collector.(same value as MEMORYSTATUSEX)

var gcMemoryInfo = GC.GetGCMemoryInfo();
installedMemory = gcMemoryInfo.TotalAvailableMemoryBytes;
// it will give the size of memory in MB
var physicalMemory = (double) installedMemory / 1048576.0;

var ram = new ManagementObjectSearcher("select * from Win32_PhysicalMemory") .Get().Cast<ManagementObject>().First();

|

var a = Convert.ToInt64(ram["Capacity"]) / 1024 / 1024 / 1024;

(richiede System.Managment.dll come riferimento, testato su C# con Framework 4.7.2)

questa procedura salva in "a" la ram totale presente in GB


ulong memory() { return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory; }

|

var b = Convert.ToDecimal(memory()) / 1024 / 1024 / 1024;

(richiede Microsoft.VisualBasics.dll come riferimento, testato su C# Framework 4.7.2)

questa procedura salva in "b" il valore della ram in GB effettivamente disponibile


Here is another, much more simply way, using .net:

// total memory
long totalPhysicalMemory = My.Computer.Info.TotalPhysicalMemory;


// unused memory
long availablePhysicalMemory = My.Computer.Info.AvailablePhysicalMemory;


// used memory
long usedMemory = totalPhysicalMemory - availablePhysicalMemory;

Solution working on Linux (.Net Core). Inspired by GitHub/Hardware.Info. Optimized to have minimal memory allocation and avg retrieval takes 0.020 ms.

private static readonly object _linuxMemoryLock = new();
private static readonly char[] _arrayForMemInfoRead = new char[200];


public static void GetBytesCountOnLinux(out ulong availableBytes, out ulong totalBytes)
{
lock (_linuxMemoryLock) // lock because of reusing static fields due to optimization
{
totalBytes = GetBytesCountFromLinuxMemInfo(token: "MemTotal:", refreshFromFile: true);
availableBytes = GetBytesCountFromLinuxMemInfo(token: "MemAvailable:", refreshFromFile: false);
}
}


private static ulong GetBytesCountFromLinuxMemInfo(string token, bool refreshFromFile)
{
// NOTE: Using the linux file /proc/meminfo which is refreshed frequently and starts with:
//MemTotal:        7837208 kB
//MemFree:          190612 kB
//MemAvailable:    5657580 kB


var readSpan = _arrayForMemInfoRead.AsSpan();


if (refreshFromFile)
{
using var fileStream = new FileStream("/proc/meminfo", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);


using var reader = new StreamReader(fileStream, Encoding.UTF8, leaveOpen: true);


reader.ReadBlock(readSpan);
}


var tokenIndex = readSpan.IndexOf(token);


var fromTokenSpan = readSpan.Slice(tokenIndex + token.Length);


var kbIndex = fromTokenSpan.IndexOf("kB");


var notTrimmedSpan = fromTokenSpan.Slice(0, kbIndex);


var trimmedSpan = notTrimmedSpan.Trim(' ');


var kBytesCount = ulong.Parse(trimmedSpan);


var bytesCount = kBytesCount * 1024;


return bytesCount;
}

Linux and Windows together - for easy copy paste. Windows code taken from the accepted answer.

public static void GetRamBytes(out ulong availableBytes, out ulong totalBytes)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
GetBytesCountOnLinux(out availableBytes, out totalBytes);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
GetBytesCountOnWindows(out availableBytes, out totalBytes);
}
else
{
throw new NotImplementedException("Not implemented for OS: " + Environment.OSVersion);
}
}


private static readonly object _winMemoryLock = new();
private static readonly MEMORYSTATUSEX _memStatus = new();


private static void GetBytesCountOnWindows(out ulong availableBytes, out ulong totalBytes)
{
lock (_winMemoryLock) // lock because of reusing the static class _memStatus
{
GlobalMemoryStatusEx(_memStatus);


availableBytes = _memStatus.ullAvailPhys;
totalBytes = _memStatus.ullTotalPhys;
}
}


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;


public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
}
}


[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GlobalMemoryStatusEx([In] [Out] MEMORYSTATUSEX lpBuffer);