2009-01-13 31 views
41

Sé cómo utilizar la memoria del sistema usando GlobalMemoryStatusEx, pero eso me dice qué está usando todo el sistema operativo.Cómo obtener la memoria utilizada por un programa Delphi

Realmente quiero que mi programa informe cuánta memoria solo ha asignado y está utilizando.

¿Hay alguna manera dentro de mi programa Delphi 2009 para llamar a una función de Windows o tal vez a alguna función de FastMM para averiguar la memoria que ha sido asignada por mi programa solo?


Revisando mi pregunta, ahora he cambiado mi respuesta aceptada a la respuesta GetMemoryManagerState por @apenwarr. Produjo resultados idénticos a la función GetHeapStatus (ahora en desuso) que solía utilizar, mientras que GetProcessMemoryInfo.WorkingSetSize dio un resultado muy diferente.

Respuesta

56

Usted puede obtener información sobre el uso de memoria útil de la ejecución Delphi sin utilizar ningún Win32 dirigir las llamadas:

function MemoryUsed: cardinal; 
var 
    st: TMemoryManagerState; 
    sb: TSmallBlockTypeState; 
begin 
    GetMemoryManagerState(st); 
    result := st.TotalAllocatedMediumBlockSize + st.TotalAllocatedLargeBlockSize; 
    for sb in st.SmallBlockTypeStates do begin 
     result := result + sb.UseableBlockSize * sb.AllocatedBlockCount; 
    end; 
end; 
------------- 
Note from Louis Kessler on 12 Feb 2018: I believe the "result :=" line should be: 
    result := st.TotalAllocatedMediumBlockSize * st.AllocatedMediumBlockCount 
       + st.TotalAllocatedLargeBlockSize * st.AllocatedLargeBlockCount; 

Also, the returned value from the function needs to be int64 rather than cardinal. 

Lo mejor de este método es que está estrictamente seguido: cuando se asigna memoria, que sube y cuando desasigna la memoria, disminuye en la misma cantidad de inmediato. Utilizo esto antes y después de ejecutar cada una de las pruebas de mi unidad, por lo que puedo decir qué prueba está perdiendo memoria (por ejemplo).

+5

Este método es válido cuando se usa FastMM4 o delphi 2006+, pero si no está utilizando FastMM4, ¡debería considerar comenzar a usarlo! –

+3

Esta puede ser la mejor y más útil respuesta que he visto en StackOverflow. Ojalá pudiera votarlo 100 veces. –

+0

Además de lo anterior, este método muestra la cantidad de memoria * asignada * por la aplicación, no la cantidad de memoria utilizada (como memoria asignada por dlls de terceros, ocx/COM, etc.) Para eso, una solución mucho más confiable es el dado por Jim McKeeth a continuación, siempre que MemCounters.PagefileUsage también se agregue al resultado. – ciuly

0

Para la forma de API de Win32, necesita función GetProcessMemoryInfo. Aquí hay un ejemplo de MSDN page pero el código está en C++. Creo que también puedes convertirlo a Delphi. Lo que estás buscando se llama probablemente "Tamaño del conjunto de trabajo".

#include <windows.h> 
#include <stdio.h> 
#include <psapi.h> 

void PrintMemoryInfo(DWORD processID) 
{ 
    HANDLE hProcess; 
    PROCESS_MEMORY_COUNTERS pmc; 

    // Print the process identifier. 

    printf("\nProcess ID: %u\n", processID); 

    // Print information about the memory usage of the process. 

    hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | 
            PROCESS_VM_READ, 
            FALSE, processID); 
    if (NULL == hProcess) 
     return; 

    if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) 
    { 
     printf("\tPageFaultCount: 0x%08X\n", pmc.PageFaultCount); 
     printf("\tPeakWorkingSetSize: 0x%08X\n", 
        pmc.PeakWorkingSetSize); 
     printf("\tWorkingSetSize: 0x%08X\n", pmc.WorkingSetSize); 
     printf("\tQuotaPeakPagedPoolUsage: 0x%08X\n", 
        pmc.QuotaPeakPagedPoolUsage); 
     printf("\tQuotaPagedPoolUsage: 0x%08X\n", 
        pmc.QuotaPagedPoolUsage); 
     printf("\tQuotaPeakNonPagedPoolUsage: 0x%08X\n", 
        pmc.QuotaPeakNonPagedPoolUsage); 
     printf("\tQuotaNonPagedPoolUsage: 0x%08X\n", 
        pmc.QuotaNonPagedPoolUsage); 
     printf("\tPagefileUsage: 0x%08X\n", pmc.PagefileUsage); 
     printf("\tPeakPagefileUsage: 0x%08X\n", 
        pmc.PeakPagefileUsage); 
    } 

    CloseHandle(hProcess); 
} 

int main() 
{ 
    // Get the list of process identifiers. 

    DWORD aProcesses[1024], cbNeeded, cProcesses; 
    unsigned int i; 

    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) 
     return 1; 

    // Calculate how many process identifiers were returned. 

    cProcesses = cbNeeded/sizeof(DWORD); 

    // Print the memory usage for each process 

    for (i = 0; i < cProcesses; i++) 
     PrintMemoryInfo(aProcesses[i]); 

    return 0; 
} 
+2

Gracias para el inicio de apagado. Respuesta correcta pero lenguaje equivocado y muy complicado. – lkessler

3

Puede ver un ejemplo sobre cómo utilizar FastMM con el proyecto UsageTrackerDemo que viene incluido con los Demos cuando se descarga el paquete FastMM4 completa de SourceForge.

4

escribí esta pequeña función para devolver la corriente de proceso (app) el uso de memoria:

function ProcessMemory: longint; 
var 
    pmc: PPROCESS_MEMORY_COUNTERS; 
    cb: Integer; 
begin 
    // Get the used memory for the current process 
    cb := SizeOf(TProcessMemoryCounters); 
    GetMem(pmc, cb); 
    pmc^.cb := cb; 
    if GetProcessMemoryInfo(GetCurrentProcess(), pmc, cb) then 
    Result:= Longint(pmc^.WorkingSetSize); 

    FreeMem(pmc); 
end; 
+1

¿Por qué usar GetMem? Simplemente declare una variable TProcessmemoryCounters allí en lugar de usar una dinámica. –

+0

Esta es la respuesta, con la optimización de Rob. – lkessler

+2

Depende de lo que piense que es el uso de la memoria. Este código le da el tamaño del conjunto de trabajo y es lo que el administrador de tareas llama uso de memoria. Pero de lejos no es la cantidad de memoria que usa un proceso. Es la parte que actualmente está en RAM en lugar del archivo de página. –

20

From an old blog post of mine.

¿Desea saber cuánta memoria está usando su programa? Esta función Delphi hará el truco.

uses psAPI; 

{...} 

function CurrentProcessMemory: Cardinal; 
var 
    MemCounters: TProcessMemoryCounters; 
begin 
    MemCounters.cb := SizeOf(MemCounters); 
    if GetProcessMemoryInfo(GetCurrentProcess, 
     @MemCounters, 
     SizeOf(MemCounters)) then 
    Result := MemCounters.WorkingSetSize 
    else 
    RaiseLastOSError; 
end; 

No está seguro de dónde saqué los fundamentos de esto, pero he añadido un poco de mejor manejo a que el error y lo hice una función. WorkingSetSize es la cantidad de memoria utilizada actualmente. Puede usar un código similar para obtener otros valores para el proceso actual (o cualquier proceso). Deberá incluir psAPI en su declaración de usos.

El PROCESS_MEMORY_COUNTERS registro incluye:

  • PageFaultCount
  • PeakWorkingSetSize
  • WorkingSetSize
  • QuotaPeakPagedPoolUsage
  • QuotaPagedPoolUsage
  • QuotaPeakNonPagedPoolUsage
  • QuotaNonPagedPoolUsage
  • PagefileUsage
  • PeakPagefileUsage

Puede encontrar todos estos valores en el Administrador de tareas o el Explorador de procesos.

+0

Lo siento Jim. Gerard lo consiguió primero. – lkessler

0

Conversión de Gant código C++, a la consola de aplicación en Delphi:

program MemoryProcessCMD; 

    {* Based in Gant(https://stackoverflow.com/users/12460/gant) code*} 


    {$APPTYPE CONSOLE} 
    {$R *.res} 

    uses 
     System.SysUtils, 
     psapi, 
     Windows; 

    procedure PrintMemoryInfo(processID: DWORD); 
    var 
     hProcess: THandle; 
     pmc: PROCESS_MEMORY_COUNTERS; 
     total: DWORD; 

    begin 

     // Print the process identifier. 
     Writeln(format('Process ID: %d', [processID])); 

     // Print information about the memory usage of the process. 
     hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, 
     processID); 

     if (hProcess = 0) then 
     begin 
     exit; 
     end; 

     if (GetProcessMemoryInfo(hProcess, @pmc, SizeOf(pmc))) then 
     begin 
     Writeln(format(#09'PageFaultCount: 0x%.8X', [pmc.PageFaultCount])); 
     Writeln(format(#09'PeakWorkingSetSize: 0x%.8X', [pmc.PeakWorkingSetSize])); 
     Writeln(format(#09'WorkingSetSize: 0x%.8X', [pmc.WorkingSetSize])); 
     Writeln(format(#09'QuotaPeakPagedPoolUsage: 0x%.8X', 
      [pmc.QuotaPeakPagedPoolUsage])); 
     Writeln(format(#09'QuotaPagedPoolUsage: 0x%.8X', 
      [pmc.QuotaPagedPoolUsage])); 
     Writeln(format(#09'QuotaPeakNonPagedPoolUsage: 0x%.8X', 
      [pmc.QuotaPeakNonPagedPoolUsage])); 
     Writeln(format(#09'QuotaNonPagedPoolUsage: 0x%.8X', 
      [pmc.QuotaNonPagedPoolUsage])); 
     Writeln(format(#09'PagefileUsage: 0x%.8X', [pmc.PagefileUsage])); 
     Writeln(format(#09'PeakPagefileUsage: 0x%.8X', [pmc.PeakPagefileUsage])); 
     Writeln(format(#09'PagefileUsage: 0x%.8X', [pmc.PagefileUsage])); 
     end; 

     CloseHandle(hProcess); 
    end; 

    var 
     aProcesses: array [0 .. 1024] of DWORD; 
     cbNeeded, cProcesses: DWORD; 
     i: Integer; 

    begin 
     try 
     // Get the list of process identifiers. 
     if (not EnumProcesses(@aProcesses, SizeOf(aProcesses), &cbNeeded)) then 
      halt(1); 

     // Calculate how many process identifiers were returned. 
     cProcesses := cbNeeded div SizeOf(DWORD); 

     // Print the memory usage for each process 
     for i := 0 to cProcesses - 1 do 
     begin 
      PrintMemoryInfo(aProcesses[i]); 
     end; 
     except 
     on E: Exception do 
      Writeln(E.ClassName, ': ', E.Message); 
     end; 

    end. 
Cuestiones relacionadas