Como você obtém a quantidade total de RAM do computador?

88

Usando C #, desejo obter a quantidade total de RAM que meu computador possui. Com o PerformanceCounter posso obter a quantidade de RAM disponível, configurando:

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

Mas não consigo encontrar uma maneira de obter a quantidade total de memória. Como eu faria isso?

Atualizar:

MagicKat: Eu vi isso quando estava procurando, mas não funciona - "Você está faltando um assembly ou referência?". Procurei adicionar isso às referências, mas não o vejo lá.

Joel
fonte

Respostas:

62

A função da API do Windows GlobalMemoryStatusExpode ser chamada com 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);

Em seguida, use como:

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

Ou você pode usar o WMI (gerenciado, mas mais lento) para consultar TotalPhysicalMemoryna Win32_ComputerSystemclasse.

Philip Rieck
fonte
2
Isso não está funcionando ... long ramuse = (long) stat.TotalPhysical; longo ramavailable = (longo) stat.AvailablePhysical; ramtotal longo = ramavailable + ramuse; porcentagem int = (int) ((float) ramuse / ramtotal * 100); por cento está me dizendo "70" e o total está mudando constantemente, mais ou menos 100. deveria ser 72%
Joel
5
O código funciona, só você não precisa usar 'NativeMethods' para obter o tamanho do objeto, você simplesmente pode dizer assim: this.dwLength = (uint)Marshal.SizeOf(this);e funciona da mesma forma (tive problemas com o uso de NativeMethods, então esta correção agora funciona).
Cipi
2
"NativeMethods" é o namespace do tipo. A chamada para SizeOf pode ser alterada se você preferir.
Philip Rieck
2
@Corelgott Inútil porque fornece informações atualizadas? Quer dizer, toda vez que eu verifico o canal do tempo ele dá informações diferentes, mas eu não iria tão longe a ponto de dizer que é totalmente inútil. Eu nem tenho certeza do que você gostaria que essa função fizesse se não retornasse informações potencialmente diferentes a cada vez - ela deveria "bloquear" os resultados após a primeira chamada e retornar dados desatualizados depois disso? De que forma isso seria mais útil?
Philip Rieck
2
Um pouco tarde para a festa, mas me deparei com este tópico e esta resposta não está correta. GlobalMemoryStatusEx não fornece necessariamente (e muitas vezes não o fará) a quantidade real de RAM instalada na máquina, mas sim a quantidade que está disponível para o SO que quase sempre é diferente da quantidade instalada devido à memória reservada para drivers, etc. Para obter a quantidade real de RAM instalada, convém chamar a função GetPhysicallyInstalledSystemMemory, que retorna a RAM total adequada. msdn.microsoft.com/en-us/library/windows/desktop/…
Mike Johnson,
182

Adicione uma referência a Microsoft.VisualBasice a using Microsoft.VisualBasic.Devices;.

A ComputerInfoaula tem todas as informações de que você precisa.

MagicKat
fonte
10
Por que diabos isso foi rejeitado? Votado de volta! Esta é a maneira mais fácil de fazer isso, e sim, você pode fazer isso em C #.
Paul Batum
54
+1: Algumas pessoas têm aversão a fazer referência ao namespace Microsoft.VisualBasic do C #, embora seja apenas outro assembly instalado como parte de todo o resto.
Bevan de
2
Retorna o valor negativo de lixo em Windows7 64 bits com 8 GB de RAM. É por isso que você não votou?
Piotr Kula
6
Para qualquer um que desconfie de usar (new ComputerInfo ()) .TotalPhysicalMemory, ele funciona bem em um sistema com ainda mais memória do que isso. Seu tipo de retorno é longo sem sinal, portanto, um número negativo não é possível sem uma conversão (inválida).
Miles Strombach
6
var totalGBRam = Convert.ToInt32 ((new ComputerInfo (). TotalPhysicalMemory / (Math.Pow (1024, 3))) + 0,5);
Sean
63

Adicione uma referência a Microsoft.VisualBasic.dll, como alguém mencionado acima. Então, obter memória física total é tão simples quanto isto (sim, eu testei):

static ulong GetTotalMemoryInBytes()
{
    return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory;
}
Ryan Lundy
fonte
4
@ppumkin, em qual versão do .NET e em qual versão do Visual Studio? Quando eu o executo no VS 2012 usando .NET 4.5 em uma máquina de 64 bits com 8 GB de RAM, ele funciona bem. Eu volto 8520327168.
Ryan Lundy
.NET 4, VS2010 32 bits no Windows Pro 7 64 bits
Piotr Kula
2
Funciona bem no x64. Você está usando um VS de 32 bits que provavelmente está compilando binários de 32 bits que não verão o tamanho total da memória.
Lucas Teske
2
Ao usar isso no Visual Studio 2017 com C # .Net 4.6.1, eu tive que adicionar uma referência para Microsoft.VisualBasic para fazer isso funcionar. Projeto> Adicionar Referência >> Assemblies> Check Microsoft.VisualBasic >> OK
WebLuke
Percebi uma diferença entre GetPhysicallyInstalledSystemMemory e Microsoft.VisualBasic.Devices.ComputerInfo (). TotalPhysicalMemory new FileSizeStruct (34173231104) {31,8 GB} ByteCount: 34173231104 ByteSize: GB Tamanho: 31688 novo FileSizeStruct (34173231104) {31,8 GB} ByteCount: 34173231104 ByteSize: GB Tamanho: 3168968 novo FileSizeStruct (343597383 GB {34359738} ByteCount: 34359738 GB {343597383 GB) {343597383 GB {343597388 GBountCountCount: 343597383 GB {343597383 GB {34359738} ByteCount Tamanho GB: 32
fanuc_bob
36

Todas as respostas aqui, incluindo a aceita, fornecerão a quantidade total de RAM disponível para uso. E pode ter sido isso que a OP queria.

Mas se você estiver interessado em obter a quantidade de RAM instalada , convém fazer uma chamada para a função GetPhysicallyInstalledSystemMemory .

A partir do link, na seção Comentários:

A função GetPhysicallyInstalledSystemMemory recupera a quantidade de RAM fisicamente instalada das tabelas de firmware SMBIOS do computador. Isso pode ser diferente da quantidade relatada pela função GlobalMemoryStatusEx , que define o membro ullTotalPhys da estrutura MEMORYSTATUSEX para a quantidade de memória física que está disponível para uso do sistema operacional. A quantidade de memória disponível para o sistema operacional pode ser menor que a quantidade de memória fisicamente instalada no computador porque o BIOS e alguns drivers podem reservar memória como regiões de E / S para dispositivos mapeados na memória, tornando a memória indisponível para o sistema operacional e aplicativos.

Código de amostra:

[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
fonte
1
Obrigado! Eu estava procurando exatamente isso, mas em todos os lugares eu só consigo ver como encontrar a memória total disponível ao invés da instalada.
SM
Não funciona bem na minha máquina virtual, apesar de funcionar perfeitamente na principal.
SM
31

Se você estiver usando o Mono, talvez se interesse em saber que o Mono 2.8 (a ser lançado ainda este ano) terá um contador de desempenho que relata o tamanho da memória física em todas as plataformas em que o Mono é executado (incluindo Windows). Você recuperaria o valor do contador usando este snippet 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);
   }
}

Se você estiver interessado no código C que fornece o contador de desempenho, ele pode ser encontrado aqui .

Grendel
fonte
funciona bem em qualquer sistema Linux, mesmo em sistemas ARM.
harry4516
14

Outra maneira de fazer isso é usando os recursos de consulta .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
fonte
Isso está jogando System.Management.ManagementException sem memória em minha máquina. Alguma ideia?
Amar
2
Eu gosto deste. Não há necessidade de referência Microsoft.VisualBasic.Devices. E como uma linhavar Capacity = new ManagementObjectSearcher("SELECT Capacity FROM Win32_PhysicalMemory").Get().Cast<ManagementObject>().Sum(x => Convert.ToInt64(x.Properties["Capacity"].Value));
VDWWD 02 de
10

Para quem está usando, .net Core 3.0não há necessidade de usar PInvokeplataforma para obter a memória física disponível. A GCclasse adicionou um novo método GC.GetGCMemoryInfoque retorna um GCMemoryInfo Structwith TotalAvailableMemoryBytescomo uma propriedade. Esta propriedade retorna a memória total disponível para o coletor de lixo. (Mesmo valor de 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
fonte
Minha resposta favorita. Obrigado.
Matas Vaitkevicius
7

você pode simplesmente usar este código para obter essas informações, basta adicionar a referência

using Microsoft.VisualBasic.Devices;

e simplesmente usar o seguinte 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
fonte
não encontrado na versão .net 4.6. Quero dizer, dá namespace ComputerInfo não foi encontrado. ainda mais ... o namespace 'Dispositivos' não 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
fonte
5

Você pode usar o WMI. Encontrou um fragmento.

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
fonte
Observe que Setnão é mais necessário para VB.NET, este é o código VB6?
jrh
2

Esta função ( ManagementQuery) funciona no Windows XP e posterior:

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"))));
Lança
fonte
2
de onde vem essa BytesToMbfunção?
Cee McSharpface
@dlatikay é função interna: Private static double BytesToMb (bytes longos) {return Math.Round (bytes / 1024d / 1024d, 2); }
Lance
1

Compatível com .Net e Mono (testado com Win10 / FreeBSD / CentOS)

Usando ComputerInfocódigo-fonte PerformanceCounteres para Mono e como backup 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
fonte
0

Ninguém mencionou GetPerformanceInfo ainda. As assinaturas do PInvoke estão disponíveis.

Esta função disponibiliza as seguintes informações de todo o sistema:

  • CommitTotal
  • CommitLimit
  • CommitPeak
  • PhysicalTotal
  • PhysicalAvailable
  • SystemCache
  • KernelTotal
  • KernelPaged
  • KernelNonpaged
  • Tamanho da página
  • HandleCount
  • ProcessCount
  • Contagem de fios

PhysicalTotalé o que o OP está procurando, embora o valor seja o número de páginas, portanto, para converter em bytes, multiplique pelo PageSizevalor retornado.

Roman Starkov
fonte
0

.NIT tem um limite para a quantidade de memória que pode acessar do total. Há uma porcentagem e 2 GB no xp era o limite máximo.

Você poderia ter 4 GB nele e mataria o aplicativo quando atingisse 2 GB.

Também no modo de 64 bits, há uma porcentagem de memória que você pode usar fora do sistema, então não tenho certeza se você pode pedir tudo ou se isso é especificamente protegido.

DevelopingChris
fonte
/Não/. Memória física total significa a memória real fisicamente instalada.
Matthew Flaschen
Na verdade, DevelopingChris está correto. Se você chamar GlobalMemoryStatusEx em uma máquina XP com 4 Gig de Ram, ele informará que há apenas 3 Gig instalados.
epotter
Além disso, usar o WMI para consultar TotalPhysicalMemory em Win32_ComputerSystem ou Win32_LogicalMemoryConfiguration também produz o resultado errado.
epotter
obrigado, não é que eu não entenda a questão, é que você tem que usar uma fonte diferente para as informações além de uma biblioteca .net.
DevelopingChris
Essa resposta é a única que faz sentido. Eu cansei agora no Win 64 8 Gb de RAM usando o VisualBasic referenciado. Recebo valores negativos de lixo.
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
fonte
6
Isso pode ser graças aos conversores online de Visual Basic para CShap.
Nick Binnet