Jak uzyskać całkowitą ilość pamięci RAM w komputerze?

88

Za pomocą języka C # chcę uzyskać całkowitą ilość pamięci RAM, którą ma mój komputer. Dzięki PerformanceCounter mogę uzyskać ilość dostępnej pamięci RAM, ustawiając:

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

Ale nie mogę znaleźć sposobu, aby uzyskać całkowitą ilość pamięci. Jak bym to zrobił?

Aktualizacja:

MagicKat: Widziałem to, kiedy szukałem, ale to nie działa - „Brakuje Ci zestawu lub referencji?”. Chciałem dodać to do odniesień, ale nie widzę tego tam.

Joel
źródło

Odpowiedzi:

62

Funkcję Windows API GlobalMemoryStatusExmożna wywołać za pomocą 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);

Następnie użyj:

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

Lub możesz użyć WMI (zarządzanej, ale wolniejszej) do wykonywania zapytań TotalPhysicalMemoryw Win32_ComputerSystemklasie.

Philip Rieck
źródło
2
To nie działa ... long ramuse = (long) stat.TotalPhysical; long ramavailable = (long) stat.AvailablePhysical; długi ramtotal = ramavailable + ramuse; int percent = (int) ((float) ramuse / ramtotal * 100); procent mówi mi "70", a suma ciągle się zmienia, daje lub bierze 100. powinno wynosić 72%
Joel
5
Kod działa, tylko nie musisz używać 'NativeMethods', aby uzyskać rozmiar obiektu, możesz po prostu powiedzieć w ten sposób: this.dwLength = (uint)Marshal.SizeOf(this);i działa tak samo (miałem problem z używaniem NativeMethods, więc ta poprawka teraz działa).
Cipi
2
„NativeMethods” to przestrzeń nazw typu. Jeśli wolisz, wywołanie SizeOf można zmienić.
Philip Rieck,
2
@Corelgott Useless, ponieważ zawiera aktualne informacje? Chodzi mi o to, że za każdym razem, gdy sprawdzam kanał pogodowy, podaje różne informacje, ale nie posunąłbym się tak daleko, aby nazwać go całkowicie bezużytecznym. Nie jestem nawet pewien, co chciałbyś, aby ta funkcja robiła, gdyby za każdym razem nie zwracała potencjalnie różnych informacji - czy powinna „blokować” wyniki po pierwszym wywołaniu, a następnie zwracać nieaktualne dane? W jaki sposób byłoby to bardziej przydatne?
Philip Rieck,
2
Trochę za późno na imprezę ale trafiłem na ten wątek i ta odpowiedź nie jest poprawna. GlobalMemoryStatusEx niekoniecznie (i często nie) podaje rzeczywistą ilość pamięci RAM zainstalowanej na komputerze, podaje ilość dostępną dla systemu operacyjnego, która prawie zawsze jest inna niż ilość zainstalowana z powodu zarezerwowanej pamięci dla sterowników itp. Aby uzyskać rzeczywistą ilość zainstalowanej pamięci RAM, powinieneś wywołać funkcję GetPhysicallyInstalledSystemMemory, która zwraca właściwą całkowitą ilość pamięci RAM. msdn.microsoft.com/en-us/library/windows/desktop/…
Mike Johnson
182

Dodaj odniesienie do Microsoft.VisualBasici using Microsoft.VisualBasic.Devices;.

ComputerInfoKlasa posiada wszystkie informacje, które potrzebujesz.

MagicKat
źródło
10
Dlaczego do licha to głosowanie odrzucono? Zagłosowano ponownie! To najłatwiejszy sposób na zrobienie tego i tak, możesz to zrobić w C #.
Paul Batum,
54
+1: Niektórzy ludzie mają awersję do odwoływania się do przestrzeni nazw Microsoft.VisualBasic z C #, mimo że jest to po prostu kolejny zestaw, który jest instalowany jako część wszystkiego innego.
Bevan
2
Zwraca ujemną wartość śmieci w systemie Windows7 64-bitowym z 8 GB pamięci RAM. To dlatego zostałeś wybrany w dół?
Piotr Kula
6
Dla każdego, kto nie chce używać (new ComputerInfo ()). TotalPhysicalMemory, działa dobrze na systemie z jeszcze większą ilością pamięci. Jego typ zwracany jest bez znaku, więc liczba ujemna nie jest możliwa bez (nieprawidłowego) rzutowania.
Miles Strombach,
6
var totalGBRam = Convert.ToInt32 ((new ComputerInfo (). TotalPhysicalMemory / (Math.Pow (1024, 3))) + 0.5);
Sean
63

Dodaj odwołanie do Microsoft.VisualBasic.dll, jak ktoś wspomniany powyżej. Uzyskanie całkowitej pamięci fizycznej jest tak proste (tak, testowałem to):

static ulong GetTotalMemoryInBytes()
{
    return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory;
}
Ryan Lundy
źródło
4
@ppumkin, w jakiej wersji .NET i w jakiej wersji programu Visual Studio? Kiedy uruchamiam go w VS 2012 przy użyciu .NET 4.5 na komputerze 64-bitowym z 8 GB pamięci RAM, działa dobrze. Wracam 8520327168.
Ryan Lundy
.NET 4, VS2010 32bit na Windows Pro 7 64bit
Piotr Kula
2
Działa dobrze na x64. Używasz 32-bitowego VS, który prawdopodobnie kompiluje 32-bitowe pliki binarne, które nie widzą pełnego rozmiaru pamięci.
Lucas Teske
2
Używając tego w programie Visual Studio 2017 z C # .Net 4.6.1, musiałem dodać odwołanie do Microsoft.VisualBasic, aby to zadziałało. Projekt> Dodaj odniesienie >> Złożenia> Sprawdź Microsoft.VisualBasic >> OK
WebLuke
Zauważyłem różnicę między GetPhysicallyInstalledSystemMemory i Microsoft.VisualBasic.Devices.ComputerInfo (). TotalPhysicalMemory new FileSizeStruct (34173231104) {31,8 GB} ByteCount: 34173231104 ByteSize: GB Rozmiar: 31,8 new FileSizeStruct (34173231104) {31,8 GB} ByteCount: 34173231104 ByteSize: GB Size: 31,8 new FileCizeStruct388398 (34173231104) Rozmiar GB: 32
fanuc_bob
36

Wszystkie odpowiedzi tutaj, w tym zaakceptowana, podają całkowitą ilość dostępnej pamięci RAM . I być może tego chciał OP.

Ale jeśli jesteś zainteresowany uzyskaniem ilości zainstalowanej pamięci RAM, będziesz chciał wykonać wywołanie funkcji GetPhysicallyInstalledSystemMemory .

Z linku w sekcji Uwagi:

Funkcja GetPhysicallyInstalledSystemMemory pobiera ilość fizycznie zainstalowanej pamięci RAM z tabel oprogramowania układowego SMBIOS komputera. Może się ona różnić od ilości zgłoszonej przez funkcję GlobalMemoryStatusEx , która ustawia element członkowski ullTotalPhys struktury MEMORYSTATUSEX na ilość pamięci fizycznej, która jest dostępna dla systemu operacyjnego. Ilość pamięci dostępnej dla systemu operacyjnego może być mniejsza niż ilość pamięci fizycznie zainstalowanej w komputerze, ponieważ system BIOS i niektóre sterowniki mogą rezerwować pamięć jako regiony we / wy dla urządzeń mapowanych w pamięci, przez co pamięć jest niedostępna dla systemu operacyjnego i aplikacje.

Przykładowy kod:

[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
źródło
1
Dziękuję Ci! Szukałem dokładnie tego, ale wszędzie widzę tylko, jak znaleźć całkowitą dostępną pamięć, a nie zainstalowaną.
SM
Nie działa jednak dobrze na mojej maszynie wirtualnej, mimo że działa doskonale na głównej.
SM
31

Jeśli używasz Mono, możesz być zainteresowany, aby wiedzieć, że Mono 2.8 (który zostanie wydany jeszcze w tym roku) będzie miał licznik wydajności, który zgłasza rozmiar pamięci fizycznej na wszystkich platformach, na których działa Mono (w tym Windows). Wartość licznika można pobrać za pomocą tego fragmentu kodu:

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

Jeśli jesteś zainteresowany kodem C, który zapewnia licznik wydajności, możesz go znaleźć tutaj .

grendel
źródło
działa dobrze na każdym systemie Linux, nawet w systemach ARM.
harry4516
14

Innym sposobem, aby to zrobić, jest użycie narzędzi do wykonywania zapytań .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;
zgerd
źródło
Powoduje to zgłoszenie wyjątku System.Management.ManagementException z pamięci na moim komputerze. Jakieś pomysły?
Amar
2
Podoba mi się ten. Nie ma potrzeby odniesienia Microsoft.VisualBasic.Devices. I jako jedna linijkavar Capacity = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory").Get().Cast<ManagementObject>().Sum(x => Convert.ToInt64(x.Properties["Capacity"].Value));
VDWWD
10

Dla tych, którzy korzystają, .net Core 3.0nie ma potrzeby korzystania z PInvokeplatformy w celu uzyskania dostępnej pamięci fizycznej. GCKlasa wprowadził nową metodę GC.GetGCMemoryInfo, która zwraca GCMemoryInfo Structsię TotalAvailableMemoryBytesw postaci nieruchomości. Ta właściwość zwraca całkowitą dostępną pamięć dla modułu odśmiecania pamięci. (Ta sama wartość co MEMORYSTATUSEX)

var gcMemoryInfo = GC.GetGCMemoryInfo();
installedMemory = gcMemoryInfo.TotalAvailableMemoryBytes;
// it will give the size of memory in MB
var physicalMemory = (double) installedMemory / 1048576.0;
BRAHIM Kamel
źródło
Moja ulubiona odpowiedź. Dzięki.
Matas Vaitkevicius
7

możesz po prostu użyć tego kodu, aby uzyskać te informacje, po prostu dodaj odniesienie

using Microsoft.VisualBasic.Devices;

a po prostu użyj następującego kodu

    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();
    }
Nilan Niyomal
źródło
nie znaleziono w wersji .net 4.6. Mam na myśli to, że nie znaleziono przestrzeni nazw ComputerInfo. jeszcze więcej ... przestrzeń nazw „Devices” nie istnieje.
gumuruh
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";
}
Mehul Sant
źródło
5

Możesz użyć WMI. Znalazłem fragment.

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
źródło
Zauważ, że Setnie jest już potrzebny dla VB.NET, czy to jest kod VB6?
jrh
2

Ta funkcja ( ManagementQuery) działa w systemie Windows XP i nowszych:

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

Stosowanie:

Console.WriteLine(BytesToMb(Convert.ToInt64(ManagementQuery("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem", "TotalPhysicalMemory", "root\\CIMV2"))));
Lanca
źródło
2
skąd BytesToMbpochodzi ta funkcja?
Cee McSharpface
@dlatikay to funkcja wewnętrzna: prywatne statyczne podwójne BytesToMb (długie bajty) {return Math.Round (bytes / 1024d / 1024d, 2); }
Lance,
1

Kompatybilny z .Net i Mono (testowany z Win10 / FreeBSD / CentOS)

Używanie ComputerInfokodu źródłowego is PerformanceCounterdla Mono i jako kopia zapasowa dla .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)))
            };
        }
    }
}
Soroush Falahati
źródło
0

Nikt jeszcze nie wspomniał o GetPerformanceInfo . Podpisy PInvoke są dostępne.

Ta funkcja udostępnia następujące informacje o całym systemie:

  • CommitTotal
  • CommitLimit
  • CommitPeak
  • Suma fizyczna
  • Fizyczny Dostępny
  • SystemCache
  • KernelTotal
  • KernelPaged
  • KernelNonpaged
  • Rozmiar strony
  • HandleCount
  • ProcessCount
  • Ilość wątków

PhysicalTotaljest tym, czego szuka OP, chociaż wartością jest liczba stron, więc aby przekonwertować na bajty, należy pomnożyć przez PageSizezwróconą wartość.

Roman Starkov
źródło
0

.NIT ma ograniczenie łącznej ilości pamięci, do której może uzyskać dostęp. Jest procent, a następnie 2 GB w xp to twardy sufit.

Możesz mieć w nim 4 GB i zabije aplikację, gdy osiągnie 2 GB.

Również w trybie 64-bitowym istnieje procent pamięci, którego możesz użyć poza systemem, więc nie jestem pewien, czy możesz poprosić o całość, czy też jest to specjalnie chronione.

DevelopingChris
źródło
/Nie/. Całkowita pamięć fizyczna oznacza rzeczywistą fizycznie zainstalowaną pamięć.
Matthew Flaschen
Właściwie DevelopingChris ma rację. Jeśli zadzwonisz do GlobalMemoryStatusEx na komputerze XP z 4 gigabajtami pamięci RAM, zgłosi, że zainstalowano tylko 3 Gig.
epotter
Ponadto użycie usługi WMI do wysłania zapytania TotalPhysicalMemory w Win32_ComputerSystem lub Win32_LogicalMemoryConfiguration również powoduje powstanie nieprawidłowego wyniku.
epotter
dziękuję, nie chodzi o to, że nie rozumiem pytania, że ​​musisz użyć innego źródła informacji niż biblioteka .net.
DevelopingChris
Ta odpowiedź jest jedyną, która ma sens. Zmęczyłem go teraz na Win 64 8Gb RAM przy użyciu odwołań VisualBasic. Otrzymuję śmieciowe wartości ujemne.
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");
}
SuMeeT ShaHaPeTi
źródło
6
Może to być możliwe dzięki konwerterom online Visual Basic na CShap.
Nick Binnet,