I have a service and I need to make sure that it doesn’t have a memory leak after running for a sustained length of time.  I’m doing all the good stuff in code to manage the garbage collection and I have the right tools to check for leaks in my code.  But I still want to monitor an instance of the service during regular usage.  I don’t need anything too finely grained, I just want to see if the memory usage is trending upwards.  There’s a good chance that I might have to deploy this out in the field, so I want something simple.  I could have used the Performance console, but I wanted something very simple to explain.  You can probably do this with a CScript batch file and WMI, but I wanted something fast to load and fast to exit.

What I want is to log the memory usage to a text file, with each entry timestamped.  I was able to do this with almost all off the shelf parts.  I did have to write the timestamper, but that was a trivial task.  Since the home viewers will not have my service, pick a service or app of your own and play along.  I’ll describe what I did using FireFox as a substitute for the actual service.

In the excellent PsTools suite over at SysInternals site, there is a utility named PsList.  It’s a combination of the pmon and pstat tools that works like a command line version of the “Processes” tab of Task Manager.  By default it lists information for all running processes, but you can filter it by service name or process ID.  I wrote a batch file to call PsList with the service name and the “-m” command line switch to print the memory usage.  PsList prints some banner information with the details.  Something like this:

PsList 1.26 - Process Information Lister
Copyright (C) 1999-2004 Mark Russinovich
Sysinternals - www.sysinternals.com

Process memory detail for Kremvax:

Name Pid VM WS Priv Priv Pk Faults NonP Page
firefox 3936 108952 41380 32748 36452 140201 8 54

All fine and good, but not pretty enough for a log file.  What I need was just the last line.  So I piped the output from PsList through the good ‘ol FIND command with “firefox” as the filter text.  With that, I can redirect the output to a file (with append).  I ended up creating a batch file named memlog.cmd that had the following commands:

pslist -m firefox | find "firefox" >>c:\logs\memuse.txt

That gave me the last line in a file.  But I still needed the time stamp. I thought about going through some script file sleight of hand with ECHO and DATE, but this is the Windows Server 2003 CMD.EXE.  It doesn’t have that skill set.  I could do with some 3rd party shells, but the goal is something I can deploy on a remote site without anyone having to pay for a tool or go through the hassle of installing something like Power Shell.

Time to fire up Delphi and create a little command line app that would take text coming in as standard input and send it back out as standart output, but with a timestamp prepended to the text.  The source code has less text in it than the previous sentence.  If you have Delphi, the following code will give you that mini-tool.  I used Delphi 7, any of the Win32 versions should do.


program dtEcho;

{$APPTYPE CONSOLE}

uses
SysUtils;

var
s: string;
begin
ReadLn(s);
WriteLn('[' + FormatDateTime('yyyy-mm-dd hh:mm', Now) + '] ' + s);
end.

There’s no banner or error checking.  I didn’t need any of that and I wanted to keep it light.  By adding dtEcho to my batch file like this:

pslist -m firefox | find "firefox" | dtecho >>c:\logs\memuse.txt

I now get output like this:

[2006-07-28 23:14] firefox            3936  536904   61324   51244   57384   445377     90  249
[2006-07-28 23:15] firefox 3936 538176 60844 50764 57384 449193 91 249
[2006-07-28 23:16] firefox 3936 538212 60620 50528 57384 455935 91 249

The output only goes down to the minute, I’m tracking the memory usage every 10 minutes, I didn’t need to make the timestamp that granular. If I needed it, I just need to make a slight change the dtEcho source code and it will print the seconds.

To run that batch file, I just used the scheduled tasks control panel applet and set it to run off of my account. For remote deployment, that would probably be the hardest step.

Tech Tags: