Introduction
When I started getting back into C++ to write some experimental compression algorithms, I was annoyed that I'd lost my code for tracking memory usage and that nobody else seemed to have posted anything similar. The basic principle is to override new and delete at the global scope in order to count bytes being allocated and deallocated, but getting the mechanics of this right is tricky for a beginner so I thought I'd post the code for others to use later on.
Disclaimer: The original new/delete operators shown below were cut & paste from the web, however it is common knowledge how to do this and I don't think anyone could claim ownership of the 9 lines in question.
Background
As stated, the basic principle for tracking memory usage in a C++ program is to override the new and delete operators, so that we get a chance to run some code whenever the language decides to allocate or deallocate some memory. We don't try to track objects as such, we just keep a total of the memory we've used, which should return to zero when the program is complete.
The tricky bit about this is that C++ doesn't tell us how much memory is being deallocated by a call to delete. In fact the implementation of this is compiler/platform specific. The aim for me then was to find a way to track the size of the memory associated with each pointer, but with a few constraints:
- You can't (de)allocate any memory during new/delete or you cause infinite recursion.
- You can't (de)allocate any memory before the structures are ready to store pointers.
- I wanted the usage to be easily available from anywhere else in the code.
Using the code
Here is the skeleton, which you paste into main.cpp. You'll need the includes and the two methods below the main method. This works just fine in Dev C++, and should in virtually any environment with a few simple modifications. You can also download the code with a working test project for Dev C++.
#include <cstdlib>
#include <exception>
#include <new>
int main(int argc, char *argv[])
{
system("PAUSE");
return EXIT_SUCCESS;
}
#define DEBUG_MEMORY
const int MAXLOCS = 256;
int memUsage = 0;
int memLocs[MAXLOCS];
int memSizes[MAXLOCS];
#ifdef DEBUG_MEMORY
void* operator new (size_t size)
{
if (memUsage == 0)
{
for (int x = 0; x < MAXLOCS; x++)
{
memLocs[x] = 0;
memSizes[x] = 0;
}
}
void *p=malloc(size);
memUsage += size;
for (int x = 0; x < MAXLOCS; x++)
{
if (memLocs[x] == 0)
{
memLocs[x] = (int) p;
memSizes[x] = size;
x = MAXLOCS;
}
}
return p;
}
void operator delete (void *p)
{
if (p == NULL) throw std::bad_alloc();
for (int x = 0; x < MAXLOCS; x++)
{
if (memLocs[x] == (int) p)
{
memUsage -= memSizes[x];
memLocs[x] = 0;
memSizes[x] = 0;
x = MAXLOCS;
}
}
free(p);
}
#endif
Improving the code
If you want to check for double deallocation you can simply throw an exception if the pointer you attempt to deallocate is not found. I didn't add this to the code because it clouds what the code is supposed to do, which I'm trying to demonstrate in the simplest form possible.
It should be fairly simple for someone to improve on the efficiency of the code provided that a) they don't introduce (or they otherwise handle) any dynamic allocation that will cause infinite recursion, and b) they don't introduce any memory leaks themselves attempting to use malloc and free.
As it stands this code is only suited to debugging small projects. It can track as many objects as you have memory to tag, but of course it will get incredibly slow under a heavy load. For me it was more about being able to check simple things as I get the hang of C++ again - such as what happens to local variables when you delete a class, or even just when to call delete vs delete[].
I hope someone finds this useful!
History
First release.