![]() |
PMMM - The Poor Man's Memory Monitor | |
---|---|---|
was written by Burton M. Strauss III (BStrauss@acm.org) |
PMMM is based in large part on a concept and code from Luca Deri's leaks.c, part of NTop.
I like problem solving. Even if it isn't really a problem. It was something fun and interesting to play with. You get the picture...
Existing drop-in malloc replacements seemed to be too co$tly or too complex for my simple needs. Besides, they focus on the wrong thing (for my needs). Either they make millions of mallocs terribly efficient, or they are huge, slow, complex things to allow a developer to find every single memory leak. I wanted something simple enough to leave in a long-running production program that would add enough value to overcome it's costs (maybe not in version 12.0, but certainly in versions 0.1, 0.2 and even 1.0).
Something simple. Something that would make it obvious if there was a leak in a long running program. Something that might trade some human oversight for automation - I figured that I could run my eye over a list of allocations after the program has run for six or 12 hours and - if I knew where the memory had been allocated - check for leaks based on constant growth of memory requirements and unfreed allocations. Something that produced statistics and reports - I love them! Something like this:Block # |
Size (bytes) |
Address |
Setting type@program(line) |
When |
---|---|---|---|---|
0. | 3480 | 0x804ebf8 | m@initialize.c(91) | Fri Jan 25 11:09:15 2002 |
1. | 3480 | 0x804f998 | m@initialize.c(93) | Fri Jan 25 11:09:15 2002 |
And it produced statistics about memory allocations, which does give visibility to the systems administrator about Ntop's memory usage without much impact on execution:
(Reported by malloc): | Total: | 1361044 | ||||||
---|---|---|---|---|---|---|---|---|
Used: | 1345588 | 98.9% | ||||||
Free: | 15456 | 1.1% | in 16 chunks | |||||
mmap: | 2 chunks, | 532480 bytes | ||||||
Tracking table: | 354 slots used out of 1000. Tracing allocations of at least 17 bytes table full reported flag is 0 | |||||||
Allocation size | malloc | calloc | realloc | free | Alloc. Bytes | Freed Bytes | InUse Bytes | Failed |
<= 16 bytes | 509 | 4 | 3 | 4189 | 4189 | 0 | ||
<= 256 bytes | 240 | 40 | 9 | 139 | 38043 | 25295 | 12748 | 0 |
<= 1024 bytes | 120 | 2 | 0 | 55 | 47040 | 17520 | 29520 | 0 |
<= 4096 bytes | 75 | 63 | 0 | 0 | 379472 | 0 | 379472 | 0 |
<= 16384 bytes | 2 | 0 | 0 | 2 | 22284 | 22284 | 0 | 0 |
<= 65536 bytes | 1 | 0 | 0 | 0 | 22284 | 0 | 22284 | 0 |
larger | 2 | 2 | 0 | 2 | 1048560 | 524272 | 524288 | 0 |
frees (size not tracked) | 656 | |||||||
Totals: | 949 | 111 | 12 | 854 | 1561872 | 589371 | 972501 | 0 |
Hog heaven - it produced statistics!
Before sending a huge, unsolicited patch to Luca Deri (the great ghu of Ntop), I asked him about it, and he suggested it could be applied more generally. Hence PMMM.
Ntop
Luca Deri's Ntop had a malloc shim in it's leaks.c module. When I started working with Ntop, there were actually two versions. One was a basic shim that didn't do much, but at least it worked (it warned the developer of a zero or large allocation, and it cleared out the buffer so unallocated space would be obvious):
void* ntop_safemalloc(unsigned int sz, char* file, int line) { void *thePtr; #ifdef DEBUG if((sz == 0) || (sz > 32768)) { traceEvent(TRACE_WARNING, "WARNING: called malloc(%u) @ %s:%d", sz, file, line); } #endif thePtr = malloc(sz); memset(thePtr, 0xee, sz); /* Fill it with garbage */ return(thePtr); }
The second version - which I couldn't get to compile - malloced a little buffer for each allocation and looked like it would make a linked list of them.
Both used a #define "shim" to insert themselves into the malloc call, rather than relying on the GCC-only hook. Of course, they were then limited to tracking allocations in the Ntop source, not from other sources. But it was neat and fairly clean.
I liked the neatness of the shim. And I love statistics about long-running programs, even if there really isn't much I can do about it.
So I started to modify the version in leaks.c that worked to be a little bit better about tracking stuff without the overhead of the malloc'ed linked list. Instead I used two static tables (allocations and statistics) and some parameters to decide what to track, vs. ignore.
It could track 100%, or by setting the parameters, only track big allocations.
For post-mortem usage, the allocation table can be dumped at the end of the run (size, pointer, from where and when allocated). This allows us to see some memory leak patterns, for example 100s of allocations from a specific place in the code.
Lastly, having our own routines could allow us to do special case tuning (such as a program managed queue of packet sized entries) if it later became desirable. See, like many programs, Ntop has unique memory access patterns, and those could - conceiveably - be taken advantage of to reduce calls to malloc, overhead, etc.
I could have left it there, incorporated it into Ntop and been a happy camper. But I've rarely been able to leave well enough alone. And besides, I needed SOMETHING to keep my mind busy on sabatical. So, the goal of the PMMM was just a little bit more...