Process Private Memory Usage Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Blue Kodiak
Posts: 26
Joined: 17 Mar 2019, 00:45

Process Private Memory Usage

20 Mar 2019, 19:17

HI,
I'm try to monitor the memory usage of a running process using the code below
borrowed from a 2014 post by Flipeador.

Code: Select all

ProcessMemoryInfo(ProcessName) {
	ProcessId := InStr(ProcessName, ".")?ProcessExist(ProcessName):ProcessName
	, hProcess := DllCall("Kernel32.dll\OpenProcess", "UInt", 0x0010|0x0400, "UInt", 0, "UInt", ProcessId)
	, nSize := VarSetCapacity(memCounters, A_PtrSize = 8 ? 72 : 40), NumPut(nSize, memCounters)
	if !(DllCall("Psapi.dll\GetProcessMemoryInfo", "Ptr", hProcess, "UInt", &memCounters, "UInt", nSize)) {
		memCounters := "", nSize := VarSetCapacity(memCounters, A_PtrSize = 8 ? 80 : 44), NumPut(nSize, memCounters)
		if !(DllCall("Kernel32.dll\K32GetProcessMemoryInfo", "Ptr", hProcess, "UInt", &memCounters, "UInt", nSize))
			return false, ErrorLevel := true
	} i := {}, i.PageFaultCount := NumGet(memCounters, 4, "UInt")
		, i.PeakWorkingSetSize := NumGet(memCounters, 8, "Ptr")
		, i.WorkingSetSize := NumGet(memCounters, A_PtrSize = 8 ? 16 : 12, "Ptr") 
		, i.QuotaPeakPagedPoolUsage := NumGet(memCounters, A_PtrSize = 8 ? 24 : 16, "Ptr")
		, i.QuotaPagedPoolUsage := NumGet(memCounters, A_PtrSize = 8 ? 32 : 20, "Ptr")
		, i.QuotaPeakNonPagedPoolUsage := NumGet( memCounters, A_PtrSize = 8 ? 40 : 24, "Ptr")
		, i.QuotaNonPagedPoolUsage := NumGet( memCounters, A_PtrSize = 8 ? 48 : 28, "Ptr")
		, i.PagefileUsage := NumGet( memCounters, A_PtrSize = 8 ? 56 : 32, "Ptr")
		, i.PeakPagefileUsage := NumGet( memCounters, A_PtrSize = 8 ? 64 : 36, "Ptr")
		, i.PrivateUsage := NumGet(memCounters, A_PtrSize = 8 ? 72 : 40, "Ptr")
	return i, DllCall("kernel32.dll\CloseHandle", "Ptr", hProcess), ErrorLevel := false
}


Issue 1.
However The the first DllCall {DllCall("Psapi.dll\GetProcessMemoryInfo", "Ptr", hProcess, "UInt", &memCounters, "UInt", nSize)}
always returns True.
Consequently The Kerne32 version is never called and consequently PrivateUsage
is never returned (the PROCESS_MEMORY_COUNTERS structure is only 72 bytes).
I could drop the PSAPI call altogether and call only the Kernel32 version but
on the Microsoft website they recommending using the PSAPI version to ensure
compatibility with older systems.

Issue 2.
If I do call just the Kernel32 version the value returned for private memory
usage does not match the value shown in TaskManager -- but all other
memory usage values do match.
Is there a way to get the same processes private memory usage that TaskManager reports?

Thanks.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Process Private Memory Usage

21 Mar 2019, 09:30

this function looks weird, it's like a windows version check should be performed somewhere in there, but isn't.

the psapi call uses the regular struct, whereas the fallback method uses the extended struct

anyway, idk what task manager shows exactly when "memory (active private working set)" for a given process is inspected (that's the default, I think), but i can tell u it's not PagefileUsage or PrivateBytes. those are Commit Size in task manager
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Process Private Memory Usage

21 Mar 2019, 10:43

Hi,

If what you mean by «Private Memory Usage» is «Private Working Set» you could get it using WMI:

Code: Select all

PID := 6380  ; specify any existent PID
MsgBox, % GetPrivateWorkingSet(PID) . " KB"

GetPrivateWorkingSet(PID) {
   bytes := ComObjGet("winmgmts:")
           .ExecQuery("Select * from Win32_PerfFormattedData_PerfProc_Process Where IDProcess=" PID)
           .ItemIndex(0).WorkingSetPrivate
   Return bytes//1024
}
I'd also like to know how it can be obtained using winapi.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Process Private Memory Usage

21 Mar 2019, 11:14

This is all news to me, but I had a go at a different script by Drozd
Maybe this is useful:

Code: Select all

    PID := DllCall("GetCurrentProcessId")
    MsgBox, % GetProcessMemoryInfo(PID, "B")
    MsgBox, % GetProcessMemoryInfo(PID, "K")
    MsgBox, % GetProcessMemoryInfo(PID, "M")

ExitApp


;-------------------------------------------------------------------------------
GetProcessMemoryInfo(PID, Units := "M") {
;-------------------------------------------------------------------------------
    is64 := (A_PtrSize = 8)
    Size := (is64 ? 80 : 44)
    VarSetCapacity(MEM, Size, 0) ; make MEM
    hProcess := DllCall("OpenProcess", UInt, 0x410, Int, 0, Ptr, PID, Ptr)

    if (hProcess) {
        if DllCall("psapi.dll\GetProcessMemoryInfo"
                , Ptr, hProcess, Ptr, &MEM, UInt, Size)
            memory := NumGet(MEM, is64 ? 16 : 12)
        DllCall("CloseHandle", Ptr, hProcess)
    }

    return Units == "B" ? (memory)                 " Bytes"
        :  Units == "K" ? (memory // 1024)         " KiBytes"
        :  Units == "M" ? (memory // 1024 // 1024) " MiBytes"
        :  "I am never reached"
}
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Process Private Memory Usage

21 Mar 2019, 11:51

wolf_II wrote: Maybe this is useful
It's not a private working set, it's a working set.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Process Private Memory Usage

21 Mar 2019, 14:33

teadrinker wrote:
21 Mar 2019, 11:51
Thank you !! :)
unfortunately, I do not know what the difference is, I did not even know there was a difference.
I am happy to learn bit-by-bit. Thank you for my lesson for the day. :)
I could have remained silent, but I learn quicker when engaging with code.
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Process Private Memory Usage

21 Mar 2019, 14:49

wolf_II wrote: I do not know what the difference is
You could read this: How to interpret Windows Task Manager?
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Process Private Memory Usage

21 Mar 2019, 14:54

Thank you again !! :)
User avatar
Blue Kodiak
Posts: 26
Joined: 17 Mar 2019, 00:45

Re: Process Private Memory Usage

21 Mar 2019, 20:09

swagfag wrote:
21 Mar 2019, 09:30
this function looks weird, it's like a windows version check should be performed somewhere in there, but isn't.
My thought also. I assume it was intended that psapi call would fail for newer versions of windows but it doesn't and it shouldn't because it's supposed to be compatible with older versions of windows.
User avatar
Blue Kodiak
Posts: 26
Joined: 17 Mar 2019, 00:45

Re: Process Private Memory Usage

21 Mar 2019, 20:19

teadrinker wrote:
21 Mar 2019, 10:43
you could get it using WMI:
I'd also like to know how it can be obtained using winapi.
That works, https://www.autohotkey.com/boards/posting.php?mode=quote&f=76&p=268808# Thank you; the api discrepancy has been bugging me for a while.
teadrinker wrote:
21 Mar 2019, 10:43
I'd also like to know how it can be obtained using winapi.
Yes me too. It would be nice to get all the metrics in one operation.
I'll give it a week for someone to provide an API solution.
If that doesn't happen then I'll accept your method as the solution.
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 04:38

Hi, jNizM

Let's see:

Code: Select all

PID := 6264  ; specify any existent PID
MsgBox, % GetPrivateWorkingSet(PID) . " KB`n" . GetProcessMemoryUsage(PID) . " KB"

GetPrivateWorkingSet(PID) {
   bytes := ComObjGet("winmgmts:")
           .ExecQuery("Select * from Win32_PerfFormattedData_PerfProc_Process Where IDProcess=" PID)
           .ItemIndex(0).WorkingSetPrivate
   Return bytes//1024
}

GetProcessMemoryUsage(ProcessID)
{
   static PMC_EX, size := NumPut(VarSetCapacity(PMC_EX, 8 + A_PtrSize * 9, 0), PMC_EX, "uint")

   if (hProcess := DllCall("OpenProcess", "uint", 0x1000, "int", 0, "uint", ProcessID)) {
      if !(DllCall("GetProcessMemoryInfo", "ptr", hProcess, "ptr", &PMC_EX, "uint", size))
         if !(DllCall("psapi\GetProcessMemoryInfo", "ptr", hProcess, "ptr", &PMC_EX, "uint", size))
            return (ErrorLevel := 2) & 0, DllCall("CloseHandle", "ptr", hProcess)
      DllCall("CloseHandle", "ptr", hProcess)
      return NumGet(PMC_EX, 8 + A_PtrSize * 8, "uptr") // 1024
   }
   return (ErrorLevel := 1) & 0
}
Did you get identical results in the message box?
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 04:52

I checked with Process Explorer (https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer)

The Memory Display from the TaskManager is the Working Set (WS) Private

'Working Set' is the amount of memory that the process currently has in physical RAM

So it depends on what do you (or the OP) wants for informations

I started a Process Explorer (AHK) Project, but its far from finsihed (https://github.com/jNizM/AHK_Process_Explorer)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 05:33

I don't understand anything. :) Did the result obtained from your script match Working Set (WS) Private from the Process Explorer?
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 05:48

Found a function in my old library.. will post it after rewrite
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 07:27

Code: Select all

MsgBox % GetWorkingSetPrivateSize(9652) " K"

GetWorkingSetPrivateSize(PID)
{
	if (DllCall("ntdll.dll\NtQuerySystemInformation", "int", 0x5, "ptr", 0, "uint", 0, "uint*", size) != 0) {
		size := VarSetCapacity(buf, size << 1, 0)
		if (DllCall("ntdll\NtQuerySystemInformation", "int", 0x5, "ptr", &buf, "uint", size, "uint*", 0) != 0)
			return (ErrorLevel := 2) & 0
		addr := &buf
		while (addr) {
			if (NumGet(addr + 80, "ptr") = PID)
				return NumGet(addr + 8, "int64") // 1024
			if !(NumGet(addr + 0, "uint"))
				break
			addr += NumGet(addr + 0, "uint")
		}
	}
	return (ErrorLevel := 1) & 0
}
Will create a full function for this with all possible information exports in Scripts and Functions later
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 07:41

You could use NumGet(addr + 80, "ptr") instead of NumGet(addr+0, 80, "ptr"). :)
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 07:44

Yes I know.. this was in my lib from 2015 where I try to understand and decrypt the NtQuerySystemInformation function :D
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Process Private Memory Usage

22 Mar 2019, 07:55

teadrinker wrote: It seems to work
But only for 64 bit AHK.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Freddie, gongnl, haomingchen1998, mmflume, ShatterCoder and 95 guests