¿Cómo se obtiene la cantidad total de RAM que tiene la computadora?

88

Usando C #, quiero obtener la cantidad total de RAM que tiene mi computadora. Con PerformanceCounter puedo obtener la cantidad de RAM disponible, configurando:

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

Pero parece que no puedo encontrar una manera de obtener la cantidad total de memoria. ¿Cómo haría esto?

Actualizar:

MagicKat: Vi eso cuando estaba buscando, pero no funciona - "¿Te falta un ensamblaje o referencia?". He buscado agregar eso a las referencias, pero no lo veo allí.

Joel
fuente

Respuestas:

62

La función de la API de Windows GlobalMemoryStatusExse puede llamar 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);

Luego usa like:

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

O puede usar WMI (administrado pero más lento) para realizar consultas TotalPhysicalMemoryen la Win32_ComputerSystemclase.

Philip Rieck
fuente
2
Eso no funciona ... long ramuse = (long) stat.TotalPhysical; long ramavailable = (largo) stat.AvailablePhysical; long ramtotal = ramavailable + ramuse; int porcentaje = (int) ((flotante) ramuse / ramtotal * 100); el porcentaje me dice "70" y el total cambia constantemente, más o menos 100. debería ser 72%
Joel
5
El código funciona, solo que no necesita usar 'NativeMethods' para obtener el tamaño del objeto, simplemente puede decir así: this.dwLength = (uint)Marshal.SizeOf(this);y funciona igual (tuve problemas con el uso de NativeMethods, por lo que esta solución ahora funciona).
Cipi
2
"NativeMethods" es el espacio de nombres del tipo. La llamada a SizeOf se puede cambiar si lo prefiere.
Philip Rieck
2
@Corelgott ¿Inútil porque da información actualizada? Es decir, cada vez que miro el canal meteorológico me da información diferente, pero no me atrevería a llamarlo totalmente inútil. Ni siquiera estoy seguro de qué le gustaría que hiciera esta función si no devolviera información potencialmente diferente cada vez. ¿Debería "bloquear" los resultados después de la primera invocación y luego devolver datos obsoletos después de eso? ¿De qué forma sería más útil?
Philip Rieck
2
Un poco tarde para la fiesta, pero me encontré con este hilo y esta respuesta no es correcta. GlobalMemoryStatusEx no necesariamente (y a menudo no lo hará) proporciona la cantidad real de RAM instalada en la máquina, proporciona la cantidad que está disponible para el sistema operativo, que casi siempre es diferente a la cantidad instalada debido a la memoria reservada para los controladores, etc. Para obtener la cantidad real de RAM instalada, debe llamar a la función GetPhysicallyInstalledSystemMemory que devuelve la RAM total adecuada. msdn.microsoft.com/en-us/library/windows/desktop/…
Mike Johnson
182

Añadir una referencia a Microsoft.VisualBasicy using Microsoft.VisualBasic.Devices;.

La ComputerInfoclase tiene toda la información que necesitas.

MagicKat
fuente
10
¿Por qué diablos se rechazó esto? ¡Votado de nuevo! Esta es la forma más fácil de hacerlo, y sí, puede hacerlo desde C #.
Paul Batum
54
+1: Algunas personas tienen aversión a hacer referencia al espacio de nombres Microsoft.VisualBasic de C #, aunque en realidad es solo otro ensamblado que se instala como parte de todo lo demás.
Bevan
2
Devuelve un valor basura negativo en Windows7 de 64 bits con 8 gb de ram. ¿Es por eso que no votaron?
Piotr Kula
6
Para cualquiera que desconfíe de usar (new ComputerInfo ()). TotalPhysicalMemory, funciona bien en un sistema con incluso más memoria que eso. Su tipo de retorno es unsigned long, por lo que un número negativo no es posible sin una conversión (no válida).
Miles Strombach
6
var totalGBRam = Convert.ToInt32 ((new ComputerInfo (). TotalPhysicalMemory / (Math.Pow (1024, 3))) + 0.5);
Sean
63

Agregue una referencia a Microsoft.VisualBasic.dll, como alguien mencionado anteriormente. Entonces, obtener la memoria física total es tan simple como esto (sí, lo probé):

static ulong GetTotalMemoryInBytes()
{
    return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory;
}
Ryan Lundy
fuente
4
@ppumkin, ¿en qué versión de .NET y en qué versión de Visual Studio? Cuando lo ejecuto en VS 2012 usando .NET 4.5 en una máquina de 64 bits con 8 GB de RAM, funciona bien. Vuelvo 8520327168.
Ryan Lundy
.NET 4, VS2010 32bit en Windows Pro 7 64bit
Piotr Kula
2
Funciona bien en x64. Está utilizando un VS de 32 bits que probablemente esté compilando binarios de 32 bits que no verán el tamaño de memoria completo.
Lucas Teske
2
Al usar esto en Visual Studio 2017 con C # .Net 4.6.1, tuve que agregar una referencia para Microsoft.VisualBasic para que esto funcione. Proyecto> Agregar referencia >> Ensamblados> Verifique Microsoft.VisualBasic >> OK
WebLuke
Noté una diferencia entre GetPhysicallyInstalledSystemMemory y Microsoft.VisualBasic.Devices.ComputerInfo (). TotalPhysicalMemory new FileSizeStruct (34173231104) {31.8 GB} ByteCount: 34173231104 ByteSize: GB Size: 31.8 nuevo FileSizeStructStructize: 343697 Tamaño GB: 32
fanuc_bob
36

Todas las respuestas aquí, incluida la aceptada, le darán la cantidad total de RAM disponible para su uso. Y eso puede haber sido lo que OP quería.

Pero si está interesado en obtener la cantidad de RAM instalada , entonces querrá hacer una llamada a la función GetPhysicallyInstalledSystemMemory .

Desde el enlace, en la sección Comentarios:

La función GetPhysicallyInstalledSystemMemory recupera la cantidad de RAM físicamente instalada de las tablas de firmware SMBIOS de la computadora. Esto puede diferir de la cantidad informada por la función GlobalMemoryStatusEx , que establece el miembro ullTotalPhys de la estructura MEMORYSTATUSEX en la cantidad de memoria física que está disponible para que la utilice el sistema operativo. La cantidad de memoria disponible para el sistema operativo puede ser menor que la cantidad de memoria instalada físicamente en la computadora porque el BIOS y algunos controladores pueden reservar memoria como regiones de E / S para dispositivos asignados en memoria, lo que hace que la memoria no esté disponible para el sistema operativo y aplicaciones.

Código de muestra:

[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
fuente
1
¡Gracias! Estaba buscando exactamente esto, pero en todas partes solo puedo ver cómo encontrar la memoria total disponible en lugar de la instalada.
SM
Sin embargo, no funciona bien en mi máquina virtual, a pesar de que funciona perfectamente en la principal.
SM
31

Si está utilizando Mono, puede que le interese saber que Mono 2.8 (que se lanzará más adelante este año) tendrá un contador de rendimiento que informa el tamaño de la memoria física en todas las plataformas en las que se ejecuta Mono (incluido Windows). Recuperaría el valor del contador usando este fragmento de código:

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

Si está interesado en el código C que proporciona el contador de rendimiento, puede encontrarlo aquí .

grendel
fuente
funciona bien en cualquier sistema Linux, incluso en sistemas ARM.
harry4516
14

Otra forma de hacer esto es usando las funciones de consulta de .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
fuente
Esto está arrojando una System.Management.ManagementException Out of Memory en mi máquina. ¿Algunas ideas?
Amar
2
Me gusta este. No es necesario hacer referencia Microsoft.VisualBasic.Devices. Y como una sola líneavar Capacity = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory").Get().Cast<ManagementObject>().Sum(x => Convert.ToInt64(x.Properties["Capacity"].Value));
VDWWD
10

Para aquellos que están usando, .net Core 3.0no es necesario usar la PInvokeplataforma para obtener la memoria física disponible. La GCclase ha agregado un nuevo método GC.GetGCMemoryInfoque devuelve un GCMemoryInfo Structcon TotalAvailableMemoryBytescomo propiedad. Esta propiedad devuelve la memoria total disponible para el recolector de basura (mismo valor que 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
fuente
Mi respuesta favorita. Gracias.
Matas Vaitkevicius
7

simplemente puede usar este código para obtener esa información, solo agregue la referencia

using Microsoft.VisualBasic.Devices;

y simplemente usa el siguiente código

    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
fuente
no se encuentra en la versión .net 4.6. Me refiero a que no se encuentra el espacio de nombres ComputerInfo. aún más ... el espacio de nombres 'Dispositivos' no existe.
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
fuente
5

Podrías usar WMI. Encontré un 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
CodeRot
fuente
Tenga en cuenta que Setya no es necesario para VB.NET, ¿es este código VB6?
jrh
2

Esta función ( ManagementQuery) funciona en Windows XP y versiones posteriores:

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

Uso:

Console.WriteLine(BytesToMb(Convert.ToInt64(ManagementQuery("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem", "TotalPhysicalMemory", "root\\CIMV2"))));
lanza
fuente
2
de donde BytesToMbviene esa funcion?
Cee McSharpface
@dlatikay su función interna: doble BytesToMb estático privado (bytes largos) {return Math.Round (bytes / 1024d / 1024d, 2); }
Lance
1

Compatible con .Net y Mono (probado con Win10 / FreeBSD / CentOS)

Usando ComputerInfocódigo fuente ys PerformanceCounterpara Mono y como respaldo para .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
fuente
0

Nadie ha mencionado GetPerformanceInfo todavía. Las firmas PInvoke están disponibles.

Esta función pone a disposición la siguiente información de todo el sistema:

  • ComprometerTotal
  • CommitLimit
  • CommitPeak
  • FísicoTotal
  • FísicoDisponible
  • SystemCache
  • KernelTotal
  • KernelPaged
  • KernelNonpaged
  • Tamaño de página
  • HandleCount
  • ProcessCount
  • Número de hilos

PhysicalTotales lo que busca el OP, aunque el valor es el número de páginas, por lo que para convertir a bytes, multiplica por el PageSizevalor devuelto.

Roman Starkov
fuente
0

.NIT tiene un límite a la cantidad de memoria a la que puede acceder del total. Hay un porcentaje, y luego 2 GB en XP fue el límite máximo.

Podría tener 4 GB y mataría la aplicación cuando llegara a 2 GB.

También en el modo de 64 bits, hay un porcentaje de memoria que puede usar fuera del sistema, por lo que no estoy seguro si puede pedirlo todo o si está específicamente protegido.

DesarrollandoChris
fuente
/No/. La memoria física total significa la memoria real instalada físicamente.
Matthew Flaschen
En realidad, DevelopingChris tiene razón. Si llama a GlobalMemoryStatusEx en una máquina XP con 4 Gig de RAM, informará que solo hay 3 Gig instalados.
epotter
Además, el uso de WMI para consultar TotalPhysicalMemory en Win32_ComputerSystem o Win32_LogicalMemoryConfiguration también produce un resultado incorrecto.
epotter
gracias, no es que no entienda la pregunta, es que tienes que usar una fuente diferente para la información que no sea una biblioteca .net.
DevelopingChris
Esta respuesta es la única que tiene sentido. Lo cansé ahora en Win 64 8Gb ram usando VisualBasic referenciado. Recibo valores negativos basura.
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
fuente
6
Eso podría ser gracias a los convertidores en línea de Visual Basic a CShap.
Nick Binnet