Process memory usage

Here are some tips about getting/controlling the memory usage of a given process…

Current memory usage
You can use GetProcessMemoryInfo() API function to get the current memory usage (in bytes), peak usage, number of bytes in pagefile currently used by a process, and so on. Add Windows to your uses clause and use something like this :

procedure ShowMemUsage(PID:Cardinal);
var
    memCounters:_PROCESS_MEMORY_COUNTERS;
    h:cardinal;
begin
    ZeroMemory(@memCounters,sizeof(memCounters));
    h:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, PID);
    if h<>0 then begin
        memCounters.cb := sizeof(memCounters);
        if not GetProcessMemoryInfo(h, @memCounters, sizeof(memCounters)) then
            showmessage('Coulnd''t get memory info!')
        else
            showmessage('Current : '+inttostr(memCounters.WorkingSetSize shr 10)+' K'#13#10+'Peak : '+inttostr(memCounters.PeakWorkingSetSize shr 10 )+' K'#13#10+'Pagefile : '+inttostr(memCounters.PageFaultCount shr 10)+' K');
        closehandle(h);
    end;
end;

Memory limits
GetProcessWorkingSetSize() will give you the minimum and maximum amount of physical memory that may be used by a process. SetProcessWorkingSetSize() allows you to set new limits. Note that Windows OS treats these values as a “friendly suggestion”, so there is no guarantee they will be adhered to.

Get the minimum/maximum limits (in bytes) :

h,mMin,mMax:cardinal;
{...}
h:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, PID);
GetProcessWorkingSetSize(h,mMin,mMax);
CloseHandle(h);

Set limits :

h,newMin,newMax:cardinal;
{...}
h:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_SET_QUOTA, false, PID);
SetProcessWorkingSetSize(h, newMin, newMax);

You can also send a process to the cache (swap it out of memory) by calling SetProcessWorkingSetSize(h, $FFFFFFFF, $FFFFFFFF) , though that will only give a temporary effect and the process will be swapped back if it is actively working on some task.

Many so-called “memory managers” and “optimizers” rely on these functions to “defragment” memory, etc – when a process is sent to cache, only active and neccessary parts are swapped back to RAM, so its memory usage becomes somewhat optimized. Working set sizes can theoretically be manipulated to achieve better memory subsystem perfomance, but that would require intimate knowledge of how Windows manages RAM and memory management in general. So I’m currently rather sceptical about aforementioned utilities.

I hope this info will be useful to you 🙂

Related posts :

2 Responses to “Process memory usage”

  1. Steven says:

    Thanks for this article. Very helpful!

  2. Ivan says:

    Humm… Interesting but this doesn’t corresponds to the PrivateWorkingSet of the TaskManager on Windows 7 (and I assume Windows Vista too). It seems that further calculations needs to be done in order to obtain the PrivateWorkingSet as detailed in here http://msdn.microsoft.com/en-us/library/aa965225(v=VS.85).aspx at the bottom:

    Private working set

    To calculate this quantity, not present in PROCESS_MEMORY_COUNTERS_EX, call QueryWorkingSet() to read all the page entries into a buffer. Then count the number of entries where PSAPI_WORKING_SET_INFORMATION::WorkingSetInfo[nI].Shared is false. Multiply that by the bytes-per-page size (SYSTEM_INFO::dwPageSize) using GetSystemInfo() to get the total private working set (which is not the same as the committed private bytes PrivateUsage.

    What would be the code implementation?

Leave a Reply