How to get the Memory Used by a Delphi Program

DelphiMemory ManagementFastmm

Delphi Problem Overview


I know how to get the System memory use using GlobalMemoryStatusEx, but that tells me the what the entire OS is using.

I really want my program to report how much memory it alone has allocated and is using.

Is there any way within my Delphi 2009 program to call either a Windows function or maybe some FastMM function to find out the memory that has been allocated by my program alone?


Revisiting my question, I have now changed my accepted answer to the GetMemoryManagerState answer by @apenwarr. It produced identical results to the GetHeapStatus function (now deprecated) that I used to use, whereas GetProcessMemoryInfo.WorkingSetSize gave a very different result.

Delphi Solutions


Solution 1 - Delphi

You can get useful memory usage information out of the Delphi runtime without using any direct Win32 calls:

unit X;

uses  FastMM4; //include this or method will return 0.
....

function GetMemoryUsed: UInt64;
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;

The best thing about this method is that it's strictly tracked: when you allocate memory, it goes up, and when you deallocate memory, it goes down by the same amount right away. I use this before and after running each of my unit tests, so I can tell which test is leaking memory (for example).

Solution 2 - Delphi

From an old blog post of mine.

Want to know how much memory your program is using? This Delphi function will do the trick.

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;

Not sure where I got the basics of this, but I added some better error handling to it and made it a function. WorkingSetSize is the amount of memory currently used. You can use similar code to get other values for the current process (or any process). You will need to include psAPI in your uses statement.

The PROCESS_MEMORY_COUNTERS record includes:

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

You can find all of these values in Task Manager or Process Explorer.

Solution 3 - Delphi

You can look at an example on how to use FastMM with the UsageTrackerDemo project that comes included with the Demos when you download the complete FastMM4 bundle from SourceForge.

Solution 4 - Delphi

I wrote this small function to return the current process (app) memory usage:

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;

Solution 5 - Delphi

Conversion of Gant C ++ code, to console application in 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.

Solution 6 - Delphi

For Win32 API way, you need GetProcessMemoryInfo function. Here is an example from MSDN page but the code is in C++. I think you can convert it to Delphi as well. What you are looking is probably called "Working Set Size."

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlkesslerView Question on Stackoverflow
Solution 1 - DelphiapenwarrView Answer on Stackoverflow
Solution 2 - DelphiJim McKeethView Answer on Stackoverflow
Solution 3 - DelphiFrancescaView Answer on Stackoverflow
Solution 4 - Delphiuser34411View Answer on Stackoverflow
Solution 5 - DelphiMaicon FernandoView Answer on Stackoverflow
Solution 6 - DelphiGantView Answer on Stackoverflow