Introduction
There are many task managers for Windows Mobile out there, but I've never seen one that shows how much memory is being used by each process. I found this odd until I started digging into why. Microsoft hasn't provided the standard APIs for querying for a process' memory usage because memory works differently on WM. Fortunately, they did provide the Toolhelp32 APIs. This article implements a Task Manager for Windows Mobile that utilizes the Toolhelp32 library to take a snapshot of the heap and tally the memory usage for every process.
Background
The company I work for recently implemented a new mobile email solution. I found my phone/PPC's memory was frequently around 1MB even though the Task Manager that comes with WM didn't list any running processes. I decided to write a quick utility to walk active processes, and found the built-in task manager was only displaying processes which had a main window. I turned that utility into version 0.5 which displayed all processes, let me kill them, etc. I still hadn't answered my question about which process was chewing up my memory and if it was associated with the new email solution. I was frustrated by the lack of APIs for finding memory usage statistics. I needed to know how much memory the processes associated with my company's email solution was using, so I dug deeper. What I've published here is my final solution.
Using the Code
I won't spend much time describing how the application as a whole works, it's pretty standard. There is a file named Toolhelp32.cs which contains all the P/Invoke signatures needed to use the Toolhelp32 library. Below is the block of code that does the grunt work.
uint GetMemUsage(uint ProcId)
{
uint MemUsage = 0;
IntPtr hHeapSnapshot =
Toolhelp32.CreateToolhelp32Snapshot(Toolhelp32.TH32CS_SNAPHEAPLIST, ProcId);
if (hHeapSnapshot != INVALID_HANDLE_VALUE)
{
Toolhelp32.HEAPLIST32 HeapList = new Toolhelp32.HEAPLIST32();
HeapList.dwSize = (uint)Marshal.SizeOf(HeapList);
if (Toolhelp32.Heap32ListFirst(hHeapSnapshot, ref HeapList))
{
do
{
Toolhelp32.HEAPENTRY32 HeapEntry = new Toolhelp32.HEAPENTRY32();
HeapEntry.dwSize = (uint)Marshal.SizeOf(HeapEntry);
if (Toolhelp32.Heap32First(hHeapSnapshot, ref HeapEntry,
HeapList.th32ProcessID, HeapList.th32HeapID))
{
do
{
MemUsage += HeapEntry.dwBlockSize;
} while (Toolhelp32.Heap32Next(hHeapSnapshot, ref HeapEntry));
}
} while (Toolhelp32.Heap32ListNext(hHeapSnapshot, ref HeapList));
}
Toolhelp32.CloseToolhelp32Snapshot(hHeapSnapshot);
}
return MemUsage;
}
CreateToolhelp32Snapshot
creates a snapshot of processes, threads, heaps, and modules of a process. I pass in the TH32CS_SNAPHEAPLIST
, telling it I want information about the heap list. Once I have the snapshot, I walk the heaplists with the Heap32ListFirst
and Heap32ListNext
calls. For each list, I walk the heap with Heap32First
and Heap32Next
, and add up the block sizes for each entry in each list. Voila, the total allocated blocks for a process.
Points of Interest
There are lots of great articles out there on memory management for WM. I wish I had saved them so I could post the links here. All I can say is memory management on WM, while not nearly as robust as for a desktop OS, is much more complicated. Read-up before attempting anything more than Hello World for WM. And yes, the new email solution was the culprit.
History
- Initial version posted 02/14/2008 8:50PM (EST).