Как получить общий объем оперативной памяти компьютера?

88

Используя C #, я хочу получить общий объем оперативной памяти моего компьютера. С помощью PerformanceCounter я могу получить количество доступной оперативной памяти, установив:

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

Но я не могу найти способ получить общий объем памяти. Как бы я это сделал?

Обновить:

MagicKat: Я видел это, когда искал, но не работает - «Вам не хватает сборки или ссылки?». Я пытался добавить это в список литературы, но не вижу его там.

Джоэл
источник

Ответы:

62

Функцию Windows API GlobalMemoryStatusExможно вызвать с помощью 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);

Затем используйте как:

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

Или вы можете использовать WMI (управляемый, но медленнее) для запроса TotalPhysicalMemoryв Win32_ComputerSystemклассе.

Филип Рик
источник
2
Это не работает ... long ramuse = (long) stat.TotalPhysical; long ramavailable = (длинный) stat.AvailablePhysical; длинный ramtotal = ramavailable + ramuse; int процент = (int) ((float) ramuse / ramtotal * 100); процент говорит мне "70", а общее количество постоянно меняется, плюс-минус 100. Должно быть 72%
Джоэл
5
Код работает, только вам не нужно использовать NativeMethods, чтобы получить размер объекта, вы просто можете сказать так: this.dwLength = (uint)Marshal.SizeOf(this);и он работает так же (у меня были проблемы с использованием NativeMethods, поэтому теперь это исправление работает).
Cipi
2
«NativeMethods» - это пространство имен типа. Вызов SizeOf можно изменить, если хотите.
Филип Рик,
2
@Corelgott Бесполезен, потому что он дает актуальную информацию? То есть каждый раз, когда я проверяю погодный канал, он дает разную информацию, но я бы не стал называть это совершенно бесполезным. Я даже не уверен, что бы вы хотели, чтобы эта функция делала, если бы она не возвращала каждый раз потенциально разную информацию - должна ли она «блокировать» результаты после первого вызова, а затем возвращать устаревшие данные после этого? Каким образом это было бы более полезно?
Филип Рик
2
Немного поздно на вечеринку, но я наткнулся на эту тему, и этот ответ неверен. GlobalMemoryStatusEx не обязательно (и часто не дает) фактический объем оперативной памяти, установленной на машине, он дает объем, доступный для ОС, который почти всегда отличается от установленного объема из-за зарезервированной памяти для драйверов и т. Д. • Чтобы получить фактический объем установленной ОЗУ, вам нужно вызвать функцию GetPhysicallyInstalledSystemMemory, которая возвращает правильный общий объем ОЗУ. msdn.microsoft.com/en-us/library/windows/desktop/…
Майк Джонсон,
182

Добавьте ссылку на Microsoft.VisualBasicи файл using Microsoft.VisualBasic.Devices;.

В ComputerInfoклассе есть вся необходимая информация.

MagicKat
источник
10
Почему, черт возьми, это было отклонено? Проголосовал обратно! Это самый простой способ сделать это, и да, вы можете это сделать с C #.
Пол Батум
54
+1: Некоторые люди не любят ссылаться на пространство имен Microsoft.VisualBasic из C #, хотя на самом деле это просто еще одна сборка, установленная как часть всего остального.
Беван,
2
Возвращает отрицательное значение нежелательной почты в 64-битной Windows7 с оперативной памятью 8 ГБ. Вот почему вы проголосовали?
Петр Кула
6
Для тех, кто с подозрением относится к использованию (new ComputerInfo ()). TotalPhysicalMemory, он отлично работает в системе с еще большим объемом памяти. Его возвращаемый тип - unsigned long, поэтому отрицательное число невозможно без (недопустимого) приведения.
Майлз Стромбах
6
var totalGBRam = Convert.ToInt32 ((new ComputerInfo (). TotalPhysicalMemory / (Math.Pow (1024, 3))) + 0,5);
Шон
63

Добавьте ссылку на Microsoft.VisualBasic.dll, как упоминалось выше. Тогда получить общую физическую память очень просто (да, я это тестировал):

static ulong GetTotalMemoryInBytes()
{
    return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory;
}
Райан Ланди
источник
4
@ppumkin, в какой версии .NET и в какой версии Visual Studio? Когда я запускаю его в VS 2012 с использованием .NET 4.5 на 64-битной машине с 8 ГБ ОЗУ, он работает нормально. Я вернусь 8520327168.
Райан Ланди
.NET 4, VS2010 32bit на Windows Pro 7 64bit
Петр Кула
2
Отлично работает на x64. Вы используете 32-битный VS, который, вероятно, компилирует 32-битные двоичные файлы, которые не видят полный размер памяти.
Лукас Теске
2
При использовании этого в Visual Studio 2017 с C # .Net 4.6.1 мне пришлось добавить ссылку на Microsoft.VisualBasic, чтобы заставить это работать. Проект> Добавить
ссылку
Я заметил разницу между GetPhysicallyInstalledSystemMemory и Microsoft.VisualBasic.Devices.ComputerInfo (). TotalPhysicalMemory new FileSizeStruct (34173231104) {31,8 ГБ} ByteCount: 34173231104 ByteSize: GB Размер: 31,8 new FileSizeStruct 34353835 ByteSize: 31,8 new FileSizeStruct 3435 Размер ГБ: 32
fanuc_bob
36

Все ответы здесь, включая принятый, дадут вам общий объем оперативной памяти, доступной для использования. И, возможно, это было то, что хотел OP.

Но если вас интересует объем установленной оперативной памяти, вам нужно вызвать функцию GetPhysicallyInstalledSystemMemory .

По ссылке в разделе "Примечания":

Функция GetPhysicallyInstalledSystemMemory извлекает объем физически установленной оперативной памяти из таблиц микропрограмм SMBIOS компьютера. Это может отличаться от суммы, сообщаемой функцией GlobalMemoryStatusEx , которая устанавливает член ullTotalPhys структуры MEMORYSTATUSEX равным объему физической памяти, доступной для использования операционной системой. Объем памяти, доступный для операционной системы, может быть меньше объема памяти, физически установленной в компьютере, поскольку BIOS и некоторые драйверы могут зарезервировать память в качестве областей ввода-вывода для устройств с отображением памяти, что делает память недоступной для операционной системы. и приложения.

Образец кода:

[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.");
}
sstan
источник
1
Спасибо! Я искал именно это, но везде вижу только общую доступную память, а не установленную.
SM
Однако он не работает на моей виртуальной машине, хотя отлично работает на основной.
SM
31

Если вы используете Mono, то вам может быть интересно узнать, что Mono 2.8 (который будет выпущен позже в этом году) будет иметь счетчик производительности, который сообщает размер физической памяти на всех платформах, на которых работает Mono (включая Windows). Вы можете получить значение счетчика, используя этот фрагмент кода:

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

Если вас интересует код C, который предоставляет счетчик производительности, его можно найти здесь .

грендель
источник
отлично работает в любой системе Linux, даже в системах ARM.
harry4516
14

Другой способ сделать это - использовать средства запросов .NET System.Management:

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;
згерд
источник
Это вызывает исключение System.Management.ManagementException из памяти на моем компьютере. Любые идеи?
Amar
2
Мне нравится этот. Ссылки не нужны Microsoft.VisualBasic.Devices. И как однострочныйvar Capacity = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory").Get().Cast<ManagementObject>().Sum(x => Convert.ToInt64(x.Properties["Capacity"].Value));
VDWWD 02
10

Для тех, кто использует, .net Core 3.0нет необходимости использовать PInvokeплатформу, чтобы получить доступную физическую память. GCКласс добавлен новый метод , GC.GetGCMemoryInfoкоторый возвращает GCMemoryInfo Structс TotalAvailableMemoryBytesкак свойство. Это свойство возвращает общий объем доступной памяти для сборщика мусора (то же значение, что и MEMORYSTATUSEX).

var gcMemoryInfo = GC.GetGCMemoryInfo();
installedMemory = gcMemoryInfo.TotalAvailableMemoryBytes;
// it will give the size of memory in MB
var physicalMemory = (double) installedMemory / 1048576.0;
БРАХИМ Камель
источник
Мой любимый ответ. Спасибо.
Матас Вайткявичюс
7

вы можете просто использовать этот код для получения этой информации, просто добавьте ссылку

using Microsoft.VisualBasic.Devices;

и просто используйте следующий код

    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();
    }
Нилан Нийомал
источник
не найден в версии .net 4.6. Я имею в виду, что пространство имен ComputerInfo не найдено. даже больше ... пространства имен 'Devices' не существует.
гумурух
5
// 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";
}
Мехул Сант
источник
5

Вы можете использовать WMI. Нашел отрывок.

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
CodeRot
источник
Обратите внимание, что Setбольше не требуется для VB.NET, это код VB6?
jrh
2

Эта функция ( ManagementQuery) работает в Windows XP и новее:

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

Применение:

Console.WriteLine(BytesToMb(Convert.ToInt64(ManagementQuery("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem", "TotalPhysicalMemory", "root\\CIMV2"))));
Копье
источник
2
откуда эта BytesToMbфункция?
Cee McSharpface
@dlatikay это внутренняя функция: частный статический двойной BytesToMb (длинные байты) {return Math.Round (bytes / 1024d / 1024d, 2); }
Lance
1

Совместим с .Net и Mono (протестировано с Win10 / FreeBSD / CentOS)

Использование ComputerInfoисходного кода и PerformanceCounters для Mono и в качестве резервной копии для .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)))
            };
        }
    }
}
Соруш Фалахати
источник
0

Еще никто не упомянул GetPerformanceInfo . Доступны подписи PInvoke .

Эта функция делает доступной следующую общесистемную информацию:

  • CommitTotal
  • CommitLimit
  • CommitPeak
  • PhysicalTotal
  • Физический Доступный
  • SystemCache
  • KernelTotal
  • KernelPaged
  • Ядро
  • Размер страницы
  • HandleCount
  • ProcessCount
  • Число потоков

PhysicalTotalэто то, что ищет OP, хотя значение - это количество страниц, поэтому для преобразования в байты умножьте на PageSizeвозвращаемое значение.

Роман Старков
источник
0

.NIT имеет ограничение на общий объем памяти, к которому он может получить доступ. Там процент, а то 2 ГБ в xp были жестким потолком.

У вас может быть 4 ГБ в нем, и это убьет приложение, когда оно достигнет 2 ГБ.

Также в 64-битном режиме есть процент памяти, который вы можете использовать вне системы, поэтому я не уверен, можете ли вы запросить все это целиком или это специально защищено.

РазработкаChris
источник
/ Нет /. Общая физическая память означает фактическую физически установленную память.
Мэтью Флашен,
Собственно, DevelopingChris прав. Если вы вызовете GlobalMemoryStatusEx на машине XP с 4 ГБ ОЗУ, он сообщит, что установлено только 3 ГБ.
epotter
Кроме того, использование WMI для запроса TotalPhysicalMemory в Win32_ComputerSystem или Win32_LogicalMemoryConfiguration также дает неверный результат.
epotter
спасибо, дело не в том, что я не понимаю вопроса, что вы должны использовать другой источник информации, кроме библиотеки .net.
DevelopingChris
Этот ответ - единственный, который имеет смысл. Я устал сейчас на Win 64 8Gb ram с использованием VisualBasic. Я получаю ненужные отрицательные значения.
Петр Кула
-3
/*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");
}
СУМИТ ШАХАПЕТИ
источник
6
Это может быть благодаря онлайн-конвертерам Visual Basic в CShap.
Nick Binnet