Cómo obtener la memoria utilizada por un programa Delphi
memory-management fastmm (6)
Sé cómo usar la memoria del sistema usando GlobalMemoryStatusEx, pero eso me dice qué está usando todo el sistema operativo.
Realmente quiero que mi programa informe cuánta memoria solo ha asignado y está usando.
¿Hay alguna forma 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.
Conversión de código C ++ a la aplicación de consola en Delphi:
program MemoryProcessCMD;
{* Based in Gant(https://.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.
Escribí esta pequeña función para devolver el uso actual de la memoria del proceso (aplicación):
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;
Para la forma de API Win32, necesita la función GetProcessMemoryInfo . Aquí hay un ejemplo de la página MSDN 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;
}
Puede obtener información de uso de memoria útil del tiempo de ejecución de Delphi sin utilizar ninguna llamada directa de Win32:
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 es rastreado estrictamente: cuando asigna memoria, 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).
Puede ver un ejemplo sobre cómo usar FastMM con el proyecto UsageTrackerDemo que viene incluido con las demostraciones cuando descarga el paquete FastMM4 completo de SourceForge.
De una vieja publicación de blog mía .
¿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 estoy seguro de dónde obtuve los conceptos básicos de esto, pero agregué un mejor manejo de errores y lo convertí en 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 registro PROCESS_MEMORY_COUNTERS incluye:
- PageFaultCount
- PeakWorkingSetSize
- WorkingSetSize
- QuotaPeakPagedPoolUsage
- QuotaPagedPoolUsage
- QuotaPeakNonPagedPoolUsage
- QuotaNonPagedPoolUsage
- PagefileUsage
- PeakPagefileUsage
Puede encontrar todos estos valores en el Administrador de tareas o Process Explorer.