Як отримати загальну кількість оперативної пам’яті, яку має комп’ютер?


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 = (long) stat.AvailablePhysical; long 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та a using Microsoft.VisualBasic.Devices;.

У ComputerInfoкласі є вся необхідна інформація.


10
Чому, за бога, це було проголосовано проти? Проголосував назад! Це найпростіший спосіб зробити це, і так, ви можете це зробити з C #.
Пол Батум,

54
+1: Деякі люди не хочуть посилатися на простір імен Microsoft.VisualBasic з C #, хоча насправді це просто чергова збірка, яка встановлена ​​як частина всього іншого.
Беван,

2
Повернути негативне непотрібне значення на Windows7 64bit з 8 Гб оперативної пам'яті. Ось чому ви проголосували?
Piotr Kula

6
Для тих, хто хоче використовувати (новий ComputerInfo ()). TotalPhysicalMemory, він чудово працює в системі, яка має навіть більше пам'яті. Його тип повернення не підписується довго, тому від’ємне число неможливе без (недійсного) приведення.
Miles Strombach

6
var totalGBRam = Convert.ToInt32 ((новий 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, 32-розрядна версія для Windows Pro 7, 64-розрядна версія
Пьотр Кула,

2
Чудово працює на x64.Ви використовуєте 32-бітну VS, яка, ймовірно, компілює 32-бітні двійкові файли, які не бачать повного обсягу пам'яті.
Лукас Теске

2
Використовуючи це у Visual Studio 2017 із C # .Net 4.6.1, мені довелося додати посилання на Microsoft.VisualBasic, щоб це працювало. Проект> Додати посилання >> Асамблеї> Перевірити Microsoft.VisualBasic >> Добре
WebLuke

Я помітив різницю між GetPhysicallyInstalledSystemMemory і Microsoft.VisualBasic.Devices.ComputerInfo () TotalPhysicalMemory новий FileSizeStruct (34173231104) {31.8} ГБ ByteCount :. 34173231104 ByteSize: GB Розмір: 31.8 новий FileSizeStruct (34359738368) {32} ГБ ByteCount: 34359738368 ByteSize: Розмір ГБ: 32
fanuc_bob

36

Усі відповіді тут, включаючи прийняту, дадуть вам загальну кількість оперативної пам’яті, доступної для використання. І це, можливо, було тим, що хотів ОП.

Але якщо ви зацікавлені в тому, щоб отримати обсяг встановленої оперативної пам'яті, тоді вам потрібно буде зателефонувати до функції 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.");
}

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

Якщо вас цікавить код С, який містить лічильник продуктивності, його можна знайти тут .


чудово працює на будь-якій системі 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 з пам'яті на моєму комп'ютері. Будь-які ідеї?
Амар

2
Мені цей подобається. Не потрібно посилатися Microsoft.VisualBasic.Devices. І як var Capacity = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory").Get().Cast<ManagementObject>().Sum(x => Convert.ToInt64(x.Properties["Capacity"].Value));
однокласний

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 не знайдено. навіть більше ... простору імен "Пристрої" не існує.
гумуру

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

Зверніть увагу, що 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); }
Ленс

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 .

Ця функція робить доступною таку загальносистемну інформацію:

  • CommTotal
  • CommitLimit
  • CommPeak
  • PhysicalTotal
  • Доступний
  • SystemCache
  • KernelTotal
  • KernelPaged
  • KernelNonpaged
  • Розмір сторінки
  • HandleCount
  • ProcessCount
  • ThreadCount

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


0

.NIT має обмежений обсяг пам’яті, до якого він може отримати доступ. Є відсоток, і тоді 2 ГБ в xp було жорсткою стелею.

У ньому могло бути 4 Гб, і це вбило б програму, коли вона потрапила в 2 Гб.

Також у 64-розрядному режимі є відсоток пам'яті, яку ви можете використовувати поза системою, тому я не впевнений, чи можете ви запитати все це, чи це спеціально захищено.


/Немає/. Загальна фізична пам'ять означає фактично встановлену фізично пам'ять.
Метью Флашен

Насправді DevelopingChris є правильним. Якщо ви зателефонуєте GlobalMemoryStatusEx на машині XP з 4 гігабайтами оперативної пам'яті, він повідомить, що встановлено лише 3 гігабайт.
epotter

Крім того, використання WMI для запиту TotalPhysicalMemory в Win32_ComputerSystem або Win32_LogicMemoryConfiguration також дає неправильний результат.
epotter

дякую, справа не в тому, що я не розумію питання, тому що для інформації потрібно використовувати інше джерело, крім бібліотеки .net.
DevelopingChris

Ця відповідь єдина, яка має сенс. Зараз я втомився на оперативній пам'яті Win 64 8Gb, використовуючи посилання на VisualBasic. Я отримую сміттєві негативні значення.
Piotr Kula

-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.
Нік Біннет
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.