I'm trying to track down a memory leak on a Windows 7 Embedded Panel PC. Using Perfmon I can see that the "% committed bytes in use" grows steadily at a rate of 0.77% per hour when the app in question is running. On Win XP (not embedded) systems with the same conditions it doesn't grow at all.
I'm curious to know how this metric is calculated, with a view to adding my own monitoring and logging code to the app. Using the GlobalMemoryStatus API call I can get back several numbers, but no amount of crunching that I can think of gives me the same % result as Perfmon does when monitoring the "% committed bytes in use" counter.
How can I obtain this parameter?
Update
Sample code for Delphi follows. Just create a form, drop a memo and timer onto it. Tested under Win XP.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type TPerformanceInformation = packed record
cb : DWORD ;
CommitTotal : integer;
CommitLimit : integer ;
CommitPeak : Cardinal ;
PhysicalTotal : Cardinal ;
PhysicalAvailable : Cardinal ;
SystemCache : Cardinal ;
KernelTotal : Cardinal ;
KernelPaged : integer ;
KernelNonpaged : Cardinal ;
PageSize : Cardinal ;
HandleCount : DWORD ;
ProcessCount : DWORD ;
ThreadCount : DWORD ;
end ;
TpPerformanceInformation = ^TPerformanceInformation ;
type
TForm1 = class(TForm)
Timer1: TTimer;
Memo1: TMemo;
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1 ;
function GetPerformanceInfo (
pPerformanceInformation : TpPerformanceInformation ;
cb : dword) : integer ; stdcall ; external 'psapi.dll' ;
implementation
{$R *.dfm}
procedure TForm1.Timer1Timer(Sender: TObject);
var
Status : TMemoryStatus;
PerformanceInfo : TPerformanceInformation ;
begin
Memo1.Clear ;
Status.dwLength := sizeof(TMemoryStatus) ;
GlobalMemoryStatus (Status) ;
Memo1.Lines.Add (Format ('Total memory used (%%) : %u',[Status.dwMemoryLoad])) ;
Memo1.Lines.Add (Format ('Physical memory used : %u',[(Status.dwTotalPhys - Status.dwAvailPhys)])) ;
Memo1.Lines.Add (Format ('Physical memory left : %u',[Status.dwAvailPhys])) ;
Memo1.Lines.Add (Format ('Total physical memory : %u',[Status.dwTotalPhys])) ;
Memo1.Lines.Add (Format ('Total physical used (%%): %1.2f',[100.0 * (Status.dwTotalPhys - Status.dwAvailPhys) / Status.dwTotalPhys])) ;
Memo1.Lines.Add (Format ('Total page file : %u',[Status.dwTotalPageFile])) ;
Memo1.Lines.Add (Format ('Page file used : %u',[(Status.dwTotalPageFile - Status.dwAvailPageFile)])) ;
Memo1.Lines.Add (Format ('Page file left : %u',[Status.dwAvailPageFile])) ;
Memo1.Lines.Add (Format ('Page file used (%%) : %1.2f',[100.0 * (Status.dwTotalPageFile - Status.dwAvailPageFile) / Status.dwTotalPageFile])) ;
if (GetPerformanceInfo (Addr (PerformanceInfo), Sizeof (TPerformanceInformation)) <> 0) then
begin
with PerformanceInfo do
begin
Memo1.Lines.Add (Format ('CommitTotal : %u',[CommitTotal])) ;
Memo1.Lines.Add (Format ('CommitLimit : %u',[CommitLimit])) ;
Memo1.Lines.Add (Format ('CommitPeak : %u',[CommitPeak])) ;
Memo1.Lines.Add (Format ('PhysicalTotal : %u',[PhysicalTotal])) ;
Memo1.Lines.Add (Format ('PhysicalAvailable: %u',[PhysicalAvailable])) ;
Memo1.Lines.Add (Format ('SystemCache : %u',[SystemCache])) ;
Memo1.Lines.Add (Format ('KernelTotal : %u',[KernelTotal])) ;
Memo1.Lines.Add (Format ('KernelPaged : %u',[KernelPaged])) ;
Memo1.Lines.Add (Format ('KernelNonpaged : %u',[KernelNonpaged])) ;
Memo1.Lines.Add (Format ('PageSize : %u',[PageSize])) ;
Memo1.Lines.Add (Format ('HandleCount : %u',[HandleCount])) ;
Memo1.Lines.Add (Format ('ProcessCount : %u',[ProcessCount])) ;
Memo1.Lines.Add (Format ('ThreadCount : %u',[ThreadCount])) ;
end ;
end ;
end;
end.