Wie erhält man die Gesamtmenge an RAM, über die der Computer verfügt?

87

Mit C # möchte ich die Gesamtmenge an RAM abrufen, über die mein Computer verfügt. Mit dem PerformanceCounter kann ich die Menge des verfügbaren RAM erhalten, indem ich Folgendes einstelle:

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

Aber ich kann anscheinend keinen Weg finden, um die gesamte Speichermenge zu erhalten. Wie würde ich das machen?

Aktualisieren:

MagicKat: Ich habe das gesehen, als ich gesucht habe, aber es funktioniert nicht - "Fehlt Ihnen eine Baugruppe oder Referenz?". Ich habe versucht, das zu den Referenzen hinzuzufügen, aber ich sehe es dort nicht.

Joel
quelle

Antworten:

62

Die Windows-API-Funktion GlobalMemoryStatusExkann mit p / invoke aufgerufen werden:

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

Dann benutze wie:

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

Oder Sie können WMI (verwaltet, aber langsamer) verwenden, um TotalPhysicalMemoryin der Win32_ComputerSystemKlasse abzufragen .

Philip Rieck
quelle
2
Das funktioniert nicht ... long ramuse = (long) stat.TotalPhysical; long ramavailable = (long) stat.AvailablePhysical; long ramtotal = ramavailable + ramuse; int Prozent = (int) ((float) ramuse / ramtotal * 100); Prozent sagt mir "70" und insgesamt ändert sich ständig, geben oder nehmen 100. sollte 72% sein
Joel
5
Der Code funktioniert, nur Sie müssen 'NativeMethods' nicht verwenden, um die Größe des Objekts zu ermitteln. Sie können einfach so sagen: this.dwLength = (uint)Marshal.SizeOf(this);und es funktioniert genauso (ich hatte Probleme mit der Verwendung von NativeMethods, daher funktioniert dieses Update jetzt).
Cipi
2
"NativeMethods" ist der Namespace des Typs. Der Aufruf von SizeOf kann bei Bedarf geändert werden.
Philip Rieck
2
@Corelgott Nutzlos, weil es aktuelle Informationen gibt? Ich meine, jedes Mal, wenn ich den Wetterkanal überprüfe, gibt es andere Informationen, aber ich würde nicht so weit gehen, es als völlig nutzlos zu bezeichnen. Ich bin mir nicht einmal sicher, was diese Funktion tun soll, wenn sie nicht jedes Mal potenziell unterschiedliche Informationen zurückgibt. Sollte sie die Ergebnisse nach dem ersten Aufruf "sperren" und danach veraltete Daten zurückgeben? Inwiefern wäre das nützlicher?
Philip Rieck
2
Ein bisschen spät zur Party, aber ich bin auf diesen Thread gestoßen und diese Antwort ist nicht korrekt. GlobalMemoryStatusEx gibt nicht unbedingt (und oft auch nicht) die tatsächlich auf dem Computer installierte RAM-Menge an, sondern die dem Betriebssystem zur Verfügung stehende Menge, die sich fast immer von der Menge unterscheidet, die aufgrund des reservierten Speichers für Treiber usw. Installiert wurde Um die tatsächlich installierte RAM-Größe zu erhalten, sollten Sie die Funktion GetPhysicallyInstalledSystemMemory aufrufen, die den richtigen Gesamtspeicher zurückgibt. msdn.microsoft.com/en-us/library/windows/desktop/…
Mike Johnson
181

Fügen Sie einen Verweis auf Microsoft.VisualBasicund a hinzu using Microsoft.VisualBasic.Devices;.

Die ComputerInfoKlasse verfügt über alle Informationen, die Sie benötigen.

MagicKat
quelle
10
Warum um alles in der Welt wurde dies abgelehnt? Zurück gestimmt! Dies ist der einfachste Weg, und ja, Sie können dies von C # aus tun.
Paul Batum
53
+1: Einige Leute haben eine Abneigung gegen das Verweisen auf den Microsoft.VisualBasic-Namespace von C #, obwohl es wirklich nur eine andere Assembly ist, die als Teil von allem anderen installiert wird.
Bevan
2
Rückgabe eines negativen Junk-Werts unter Windows 7 64-Bit mit 8-GB-RAM. Deshalb wurdest du gewählt?
Piotr Kula
6
Für alle, die (new ComputerInfo ()). TotalPhysicalMemory nicht verwenden möchten, funktioniert es auf einem System mit noch mehr Speicher. Der Rückgabetyp ist lange ohne Vorzeichen, daher ist eine negative Zahl ohne eine (ungültige) Umwandlung nicht möglich.
Miles Strombach
6
var totalGBRam = Convert.ToInt32 ((neues ComputerInfo (). TotalPhysicalMemory / (Math.Pow (1024, 3))) + 0,5);
Sean
63

Fügen Sie einen Verweis auf Microsoft.VisualBasic.dll hinzu, wie oben erwähnt. Dann ist es so einfach, den gesamten physischen Speicher zu erhalten (ja, ich habe ihn getestet):

static ulong GetTotalMemoryInBytes()
{
    return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory;
}
Ryan Lundy
quelle
4
@ppumkin, in welcher Version von .NET und in welcher Version von Visual Studio? Wenn ich es in VS 2012 mit .NET 4.5 auf einem 64-Bit-Computer mit 8 GB RAM ausführe, funktioniert es einwandfrei. Ich bekomme 8520327168 zurück.
Ryan Lundy
.NET 4, VS2010 32bit unter Windows Pro 7 64bit
Piotr Kula
2
Funktioniert gut auf x64.Sie verwenden einen 32-Bit-VS, der wahrscheinlich 32-Bit-Binärdateien kompiliert, bei denen nicht die volle Speichergröße angezeigt wird.
Lucas Teske
2
Bei Verwendung in Visual Studio 2017 mit C # .Net 4.6.1 musste ich eine Referenz für Microsoft.VisualBasic hinzufügen, damit dies funktioniert. Projekt> Referenz
hinzufügen
Ich habe einen Unterschied zwischen GetPhysicallyInstalledSystemMemory und Microsoft.VisualBasic.Devices.ComputerInfo () festgestellt. TotalPhysicalMemory new FileSizeStruct (34173231104) {31,8 GB} ByteCount: 34173231104 ByteSize: GB Größe: 318 GB Größe: 32
fanuc_bob
32

Alle Antworten hier, einschließlich der akzeptierten, geben Ihnen die Gesamtmenge an RAM, die zur Verwendung verfügbar ist . Und das war vielleicht das, was OP wollte.

Wenn Sie jedoch an der Menge des installierten Arbeitsspeichers interessiert sind , sollten Sie die Funktion GetPhysicallyInstalledSystemMemory aufrufen .

Über den Link im Abschnitt "Bemerkungen":

Die Funktion GetPhysicallyInstalledSystemMemory ruft die Menge des physisch installierten RAM aus den SMBIOS-Firmware-Tabellen des Computers ab. Dies kann von der von der GlobalMemoryStatusEx- Funktion gemeldeten Menge abweichen , mit der das ullTotalPhys-Mitglied der MEMORYSTATUSEX-Struktur auf die Menge an physischem Speicher festgelegt wird, die für das Betriebssystem verfügbar ist. Die für das Betriebssystem verfügbare Speichermenge kann geringer sein als die physisch auf dem Computer installierte Speichermenge, da das BIOS und einige Treiber möglicherweise Speicher als E / A-Bereiche für Geräte mit Speicherzuordnung reservieren und der Speicher für das Betriebssystem nicht verfügbar ist und Anwendungen.

Beispielcode:

[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
quelle
Danke dir! Ich habe genau danach gesucht, aber überall kann ich nur sehen, wie der gesamte verfügbare Speicher und nicht der installierte gefunden wird.
SM
Auf meiner virtuellen Maschine funktioniert es jedoch nicht gut, obwohl es auf der Hauptmaschine perfekt funktioniert.
SM
31

Wenn Sie Mono verwenden, könnte es Sie interessieren, dass Mono 2.8 (das später in diesem Jahr veröffentlicht wird) über einen Leistungsindikator verfügt, der die physische Speichergröße auf allen Plattformen angibt, auf denen Mono ausgeführt wird (einschließlich Windows). Sie würden den Wert des Zählers mit diesem Codeausschnitt abrufen:

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

Wenn Sie an C-Code interessiert sind, der den Leistungsindikator bereitstellt, finden Sie ihn hier .

grendel
quelle
funktioniert auf jedem Linux-System, auch auf ARM-Systemen.
Harry4516
14

Eine andere Möglichkeit hierfür ist die Verwendung der .NET System.Management-Abfragefunktionen:

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
quelle
Dies führt zu einer System.Management.ManagementException auf meinem Computer. Irgendwelche Ideen?
Amar
2
Ich mag diesen. Keine Notwendigkeit zu referenzieren Microsoft.VisualBasic.Devices. Und als var Capacity = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory").Get().Cast<ManagementObject>().Sum(x => Convert.ToInt64(x.Properties["Capacity"].Value));
Einzeiler
10

Für diejenigen, die verwenden, .net Core 3.0ist es nicht erforderlich, die PInvokePlattform zu verwenden, um den verfügbaren physischen Speicher zu erhalten. Die GCKlasse hat eine neue Methode hinzugefügt GC.GetGCMemoryInfo, die ein GCMemoryInfo Structwith TotalAvailableMemoryBytesals Eigenschaft zurückgibt . Diese Eigenschaft gibt den insgesamt verfügbaren Speicher für den Garbage Collector zurück (gleicher Wert wie 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
quelle
Meine Lieblingsantwort. Vielen Dank.
Matas Vaitkevicius
7

Sie können diesen Code einfach verwenden, um diese Informationen zu erhalten. Fügen Sie einfach die Referenz hinzu

using Microsoft.VisualBasic.Devices;

und verwenden Sie einfach den folgenden 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();
    }
Nilan Niyomal
quelle
nicht in der .net 4.6 Version gefunden. Ich meine, es gibt ComputerInfo Namespace nicht gefunden. noch mehr ... Namespace 'Geräte' existiert nicht.
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
quelle
5

Sie könnten WMI verwenden. Ich habe einen Ausschnitt gefunden.

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
quelle
Beachten Sie, dass dies Setfür VB.NET nicht mehr benötigt wird. Ist dies VB6-Code?
jrh
2

Diese Funktion ( ManagementQuery) funktioniert unter Windows XP und höher:

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

Verwendung:

Console.WriteLine(BytesToMb(Convert.ToInt64(ManagementQuery("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem", "TotalPhysicalMemory", "root\\CIMV2"))));
Lanze
quelle
2
Woher kommt diese BytesToMbFunktion?
Cee McSharpface
@dlatikay es ist innere Funktion: private statische doppelte BytesToMb (lange Bytes) {return Math.Round (Bytes / 1024d / 1024d, 2); }
Lance
1

Kompatibel mit .Net und Mono (getestet mit Win10 / FreeBSD / CentOS)

Verwenden von ComputerInfoQuellcode und PerformanceCounters für Mono und als Backup für .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
quelle
0

Bisher hat noch niemand GetPerformanceInfo erwähnt . PInvoke-Signaturen sind verfügbar.

Diese Funktion stellt folgende systemweite Informationen zur Verfügung:

  • CommitTotal
  • CommitLimit
  • CommitPeak
  • PhysicalTotal
  • Physisch verfügbar
  • SystemCache
  • KernelTotal
  • KernelPaged
  • KernelNonpaged
  • Seitengröße
  • HandleCount
  • ProcessCount
  • Fadenzahl

PhysicalTotalist das, wonach das OP sucht, obwohl der Wert die Anzahl der Seiten ist. Um in Bytes umzuwandeln, multiplizieren Sie mit dem zurückgegebenen PageSizeWert.

Roman Starkov
quelle
0

.NIT hat eine Begrenzung für die Speichermenge, auf die insgesamt zugegriffen werden kann. Es gibt einen Prozentsatz und dann 2 GB in XP war die harte Decke.

Sie könnten 4 GB enthalten, und es würde die App töten, wenn es 2 GB erreicht.

Auch im 64-Bit-Modus gibt es einen Prozentsatz des Speichers, den Sie außerhalb des Systems verwenden können. Daher bin ich mir nicht sicher, ob Sie nach dem Ganzen fragen können oder ob dies speziell geschützt ist.

Entwicklung von Chris
quelle
/Nein/. Der gesamte physische Speicher bedeutet den tatsächlich physisch installierten Speicher.
Matthew Flaschen
Tatsächlich ist DevelopingChris korrekt. Wenn Sie GlobalMemoryStatusEx auf einem XP-Computer mit 4 Gig Ram aufrufen, wird gemeldet, dass nur 3 Gig installiert sind.
Epotter
Die Verwendung von WMI zum Abfragen von TotalPhysicalMemory in Win32_ComputerSystem oder Win32_LogicalMemoryConfiguration führt ebenfalls zu einem falschen Ergebnis.
Epotter
Vielen Dank, es ist nicht so, dass ich die Frage nicht verstehe. Es ist so, dass Sie eine andere Quelle für die Informationen als eine .net-Bibliothek verwenden müssen.
DevelopingChris
Diese Antwort ist die einzige, die Sinn macht. Ich habe es jetzt auf Win 64 8Gb RAM mit VisualBasic referenziert müde. Ich bekomme negative Junk-Werte.
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
quelle
6
Dies könnte an Online-Konvertern von Visual Basic zu CShap liegen.
Nick Binnet