Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GetProcessMemoryInfo PROCESS_MEMORY_COUNTERS_EX.PrivateUsage always 0

I'm using GetProcessMemoryInfo function to determine process memory usage by its PID.

With regular PROCESS_MEMORY_COUNTERS all works fine, but I need PrivateUsage member, that exists only in extended structure PROCESS_MEMORY_COUNTERS_EX.

There are couple of docs, that moved me to forcefully cast extended type to a basic one, otherwise my sample wont compile.

I'm still able to get value from basic members, such as PeakWorkingSetSize, but PrivateUsage is always 0. I've even tried to redefine PSAPI_VERSION - still nothing. Program just can't be compiled with PSAPI_VERSION < 2.

Here is my example.

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

void _tmain (int argc, TCHAR *argv[])
{
    // use first argument as PID
    DWORD processID = strtol(argv[1],0, 0);
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | SYNCHRONIZE,
        FALSE,
        processID);
    PROCESS_MEMORY_COUNTERS_EX pmc;
    ZeroMemory(&pmc, sizeof(PROCESS_MEMORY_COUNTERS_EX));
    // wait until process is dead
    WaitForSingleObject( hProcess , INFINITE );

    GetProcessMemoryInfo( hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc) );
    fprintf(stdout, "  PeakWorkingSetSize : %d\n", pmc.PeakWorkingSetSize);
    fprintf(stdout, "  PrivateUsage : %d\n", pmc.PrivateUsage);
    CloseHandle(hProcess);
}

I execute notepad.exe, then I put its PID to program above, and after all I close notepad and look for results but PrivateUsage is zero =( :

C:\utils>simple.exe 45656
  PeakWorkingSetSize : 6377472
  PrivateUsage : 0

C:\utils>

Any suggestions why its happening?

C:\utils>cl --version
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

Running on WIN7x64.

like image 955
zamuka Avatar asked Oct 20 '22 02:10

zamuka


1 Answers

I know it is a pretty old question and you probably won't need an answer. But you were very close. You were asking for private set memory after the process have been closed, so no memory for a process which no longer exists. Hence, Private Usage is 0.

Instead in my best opinion, you should have requested for Private set memory after a fixed interval of time until the process terminate. If you keep interval very low like 1 millisecond you could have got near end memory of the process.

Example:

PROCESS_MEMORY_COUNTERS_EX pmc;
ZeroMemory(&pmc, sizeof(PROCESS_MEMORY_COUNTERS_EX));

//do for every millisecond until process terminates
do
{
  ZeroMemory(&pmc, sizeof(PROCESS_MEMORY_COUNTERS_EX));
  GetProcessMemoryInfo( hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc) );

}while(WaitForSingleObject( hProcess , 1));

// wait until process is dead
// WaitForSingleObject( hProcess , INFINITE );
// GetProcessMemoryInfo( hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc) );
fprintf(stdout, " PeakWorkingSetSize : %d\n", pmc.PeakWorkingSetSize);
fprintf(stdout, " PrivateUsage (Bytes): %d\n", pmc.PrivateUsage);
fprintf(stdout, " PrivateUsage (KB) : %f\n",(float)pmc.PrivateUsage/1024.0);
CloseHandle(hProcess);

After carrying out above changes. The following output would be obtained

C:\>PidMemory.exe 3456
 PeakWorkingSetSize : 12427264
 PrivateUsage (Bytes): 2269184
 PrivateUsage (KB) : 2216.000000

This might sometime give zero because in some cases process has been terminated after while condition check. Thus, giving 0. A decent work around is to keep a history of PrivateUsage.

Example,

int history=0;
do
{
          ZeroMemory(&pmc, sizeof(PROCESS_MEMORY_COUNTERS_EX));
          GetProcessMemoryInfo( hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc) );
          if(pmc.PrivateUsage != 0)
              history = pmc.PrivateUsage;
}while(WaitForSingleObject( hProcess , 1));

I hope I have been useful.

like image 58
Dr. Xperience Avatar answered Oct 21 '22 23:10

Dr. Xperience