Come si ottiene la quantità totale di RAM di cui dispone il computer?


89

Utilizzando C #, voglio ottenere la quantità totale di RAM di cui dispone il mio computer. Con il PerformanceCounter posso ottenere la quantità di RAM disponibile, impostando:

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

Ma non riesco a trovare un modo per ottenere la quantità totale di memoria. Come potrei fare questo?

Aggiornare:

MagicKat: L'ho visto durante la ricerca, ma non funziona - "Ti manca un assembly o un riferimento?". Ho cercato di aggiungerlo ai riferimenti, ma non lo vedo lì.

Risposte:


63

La funzione API di Windows GlobalMemoryStatusExpuò essere chiamata con 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);

Quindi usa come:

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

Oppure puoi usare WMI (gestito ma più lento) per eseguire query TotalPhysicalMemorynella Win32_ComputerSystemclasse.


2
Non funziona ... long ramuse = (long) stat.TotalPhysical; long ramavailable = (long) stat.AvailablePhysical; lungo ramtotal = disponibile + ramuse; int percento = (int) ((float) ramuse / ramtotal * 100); la percentuale mi dice "70" e il totale cambia costantemente, dare o prendere 100. dovrebbe essere 72%
Joel

5
Il codice funziona, solo tu non hai bisogno di usare "NativeMethods" per ottenere la dimensione dell'oggetto, puoi semplicemente dire così: this.dwLength = (uint)Marshal.SizeOf(this);e funziona allo stesso modo (ho avuto problemi con l'utilizzo di NativeMethods, quindi questa correzione ora funziona).
Cipi

2
"NativeMethods" è lo spazio dei nomi del tipo. La chiamata a SizeOf può essere modificata se preferisci.
Philip Rieck

2
@Corelgott Inutile perché fornisce informazioni aggiornate? Voglio dire, ogni volta che controllo il canale meteo fornisce informazioni diverse, ma non mi spingerei a definirlo totalmente inutile. Non sono nemmeno sicuro di cosa vorresti che questa funzione facesse se non restituisse ogni volta informazioni potenzialmente diverse - dovrebbe "bloccare" i risultati dopo la prima chiamata e poi restituire dati non aggiornati? In che modo sarebbe più utile?
Philip Rieck

2
Un po 'in ritardo per la festa, ma mi è capitato su questo thread e questa risposta non è corretta. GlobalMemoryStatusEx non fornisce necessariamente (e spesso non lo farà) la quantità effettiva di RAM installata sulla macchina, ma fornisce la quantità disponibile per il sistema operativo che è quasi sempre diversa dalla quantità installata a causa della memoria riservata per i driver, ecc. Per ottenere la quantità effettiva di RAM installata, è necessario chiamare la funzione GetPhysicallyInstalledSystemMemory che restituisce la RAM totale corretta. msdn.microsoft.com/en-us/library/windows/desktop/…
Mike Johnson

183

Aggiungi un riferimento a Microsoft.VisualBasice ausing Microsoft.VisualBasic.Devices; .

La ComputerInfoclasse ha tutte le informazioni di cui hai bisogno.


10
Perché diavolo è stato bocciato? Votato di nuovo in su! Questo è il modo più semplice per farlo e sì, puoi farlo da C #.
Paul Batum

54
+1: alcune persone hanno un'avversione a fare riferimento allo spazio dei nomi Microsoft.VisualBasic da C #, anche se in realtà è solo un altro assembly installato come parte di tutto il resto.
Bevan

2
Restituisce un valore indesiderato negativo su Windows7 64 bit con 8 GB di RAM. È per questo che sei stato votato?
Piotr Kula

6
Per chiunque sia diffidente nell'utilizzo di (new ComputerInfo ()). TotalPhysicalMemory, funziona bene su un sistema con ancora più memoria di quella. Il tipo restituito è lungo senza segno, quindi un numero negativo non è possibile senza un cast (non valido).
Miles Strombach

6
var totalGBRam = Convert.ToInt32 ((new ComputerInfo (). TotalPhysicalMemory / (Math.Pow (1024, 3))) + 0,5);
Sean

63

Aggiungi un riferimento a Microsoft.VisualBasic.dll, come qualcuno menzionato sopra. Quindi ottenere la memoria fisica totale è semplice come questo (sì, l'ho testato):

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

4
@ppumkin, in quale versione di .NET e in quale versione di Visual Studio? Quando lo eseguo in VS 2012 utilizzando .NET 4.5 su una macchina a 64 bit con 8 GB di RAM, funziona bene. Torno indietro 8520327168.
Ryan Lundy

.NET 4, VS2010 32bit su Windows Pro 7 64bit
Piotr Kula

2
Funziona bene su x64. Stai usando un VS a 32 bit che probabilmente sta compilando binari a 32 bit che non vedranno la dimensione completa della memoria.
Lucas Teske

2
Quando lo si utilizza in Visual Studio 2017 con C # .Net 4.6.1, è stato necessario aggiungere un riferimento per Microsoft.VisualBasic per farlo funzionare. Progetto> Aggiungi riferimento >> Assiemi> Controlla Microsoft.VisualBasic >> OK
WebLuke

Ho notato una differenza tra GetPhysicallyInstalledSystemMemory e Microsoft.VisualBasic.Devices.ComputerInfo (). TotalPhysicalMemory new FileSizeStruct (34173231104) {31,8 GB} ByteCount: 34173231104 ByteSize: GB Size: 31,8 GB new FileSizeStruct 32353897 Dimensione GB: 32
fanuc_bob

36

Tutte le risposte qui, inclusa quella accettata, ti daranno la quantità totale di RAM disponibile per l'uso. E forse era quello che voleva OP.

Ma se sei interessato a ottenere la quantità di RAM installata , allora ti consigliamo di effettuare una chiamata alla funzione GetPhysicallyInstalledSystemMemory .

Dal link, nella sezione Osservazioni:

La funzione GetPhysicallyInstalledSystemMemory recupera la quantità di RAM installata fisicamente dalle tabelle del firmware SMBIOS del computer. Ciò può essere diverso dalla quantità riportata dalla funzione GlobalMemoryStatusEx , che imposta il membro ullTotalPhys della struttura MEMORYSTATUSEX sulla quantità di memoria fisica che è disponibile per il sistema operativo da utilizzare. La quantità di memoria disponibile per il sistema operativo può essere inferiore alla quantità di memoria fisicamente installata nel computer perché il BIOS e alcuni driver possono riservare memoria come regioni di I / O per i dispositivi mappati in memoria, rendendo la memoria non disponibile per il sistema operativo e applicazioni.

Codice d'esempio:

[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
Grazie! Stavo cercando esattamente questo ma ovunque riesco a vedere solo come trovare la memoria disponibile totale anziché quella installata.
SM

Tuttavia, non funziona bene sulla mia macchina virtuale, nonostante funzioni perfettamente su quella principale.
SM

31

Se ti capita di utilizzare Mono, potresti essere interessato a sapere che Mono 2.8 (che verrà rilasciato entro la fine dell'anno) avrà un contatore delle prestazioni che riporta la dimensione della memoria fisica su tutte le piattaforme su cui viene eseguito Mono (incluso Windows). Recupererai il valore del contatore utilizzando questo frammento di codice:

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

Se sei interessato al codice C che fornisce il contatore delle prestazioni, puoi trovarlo qui .


funziona bene su qualsiasi sistema Linux, anche su sistemi ARM.
harry4516

@ harry4516 sul mio sistema Ubuntu, PerformanceCounter non è supportato
Carlos Liu

14

Un altro modo per eseguire questa operazione è utilizzare le funzionalità di query di .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;

Questo genera un'eccezione System.Management.ManagementException Out of Memory sulla mia macchina. Qualche idea?
Amar

2
Mi piace questo. Non c'è bisogno di fare riferimento Microsoft.VisualBasic.Devices. E come one-linervar Capacity = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory").Get().Cast<ManagementObject>().Sum(x => Convert.ToInt64(x.Properties["Capacity"].Value));
VDWWD

10

Per coloro che stanno utilizzando .net Core 3.0non è necessario utilizzare la PInvokepiattaforma per ottenere la memoria fisica disponibile. La GCclasse ha aggiunto un nuovo metodo GC.GetGCMemoryInfoche restituisce a GCMemoryInfo Structcon TotalAvailableMemoryBytescome proprietà. Questa proprietà restituisce la memoria disponibile totale per il Garbage Collector. (Stesso valore di MEMORYSTATUSEX)

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

La mia risposta preferita. Grazie.
Matas Vaitkevicius

7

puoi semplicemente usare questo codice per ottenere quelle informazioni, basta aggiungere il riferimento

using Microsoft.VisualBasic.Devices;

e usa semplicemente il codice seguente

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

non si trova nella versione .net 4.6. Voglio dire che dà lo spazio dei nomi ComputerInfo non è stato trovato. ancora di più ... lo spazio dei nomi "Dispositivi" non esiste.
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";
}

5

Potresti usare WMI. Trovato uno snippit.

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

Nota che Setnon è più necessario per VB.NET, è questo codice VB6?
jrh

2

Questa funzione ( ManagementQuery) funziona su Windows XP e versioni successive:

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

Utilizzo:

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

2
da dove viene quella BytesToMbfunzione?
Cee McSharpface

@dlatikay è una funzione interna: private static double BytesToMb (long bytes) {return Math.Round (bytes / 1024d / 1024d, 2); }
Lance

1

Compatibile con .Net e Mono (testato con Win10 / FreeBSD / CentOS)

Utilizzo del ComputerInfocodice sorgente PerformanceCounteres per Mono e come backup per .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

Nessuno ha ancora menzionato GetPerformanceInfo . Le firme di PInvoke sono disponibili.

Questa funzione rende disponibili le seguenti informazioni a livello di sistema:

  • CommitTotal
  • CommitLimit
  • CommitPeak
  • PhysicalTotal
  • PhysicalAvailable
  • SystemCache
  • KernelTotal
  • KernelPaged
  • KernelNonpaged
  • Dimensioni della pagina
  • HandleCount
  • ProcessCount
  • ThreadCount

PhysicalTotalè ciò che l'OP sta cercando, sebbene il valore sia il numero di pagine, quindi per convertire in byte, moltiplicare per il PageSizevalore restituito.


0

.NIT ha un limite alla quantità di memoria a cui può accedere rispetto al totale. C'è una percentuale, e poi 2 GB in xp erano il limite massimo.

Potresti avere 4 GB in esso e ucciderebbe l'app quando raggiunge 2 GB.

Anche in modalità 64 bit, c'è una percentuale di memoria che puoi usare fuori dal sistema, quindi non sono sicuro se puoi chiedere l'intera cosa o se questo è specificamente protetto.


/No/. Per memoria fisica totale si intende la memoria effettiva installata fisicamente.
Matthew Flaschen,

In realtà, DevelopingChris ha ragione. Se chiami GlobalMemoryStatusEx su una macchina XP con 4 Gig di Ram, segnalerà che sono installati solo 3 Gig.
epotter

Inoltre, l'utilizzo di WMI per interrogare TotalPhysicalMemory in Win32_ComputerSystem o Win32_LogicalMemoryConfiguration produce anche il risultato errato.
epotter

grazie, non è che non capisca la domanda è che devi usare una fonte diversa per le informazioni diversa da una libreria .net.
DevelopingChris

Questa risposta è l'unica che abbia senso. L'ho stanco ora su Win 64 8Gb ram usando VisualBasic referenziato. Ottengo valori negativi spazzatura.
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
Ciò potrebbe essere dovuto ai convertitori online da Visual Basic a CShap.
Nick Binnet
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.