Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile

The simplest possible memory leak detector

2.17/5 (7 votes)
18 Oct 2009CPOL3 min read 27.7K   122  
C++ code showing how to track memory usage to avoid memory leaks

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++.

C++
// Includes that we need for the job. 
#include <cstdlib>
#include <exception>
#include <new>
 
// Entry point for the code. 
int main(int argc, char *argv[])
{

    // Your code starts here...
 

    system("PAUSE");
    return EXIT_SUCCESS;
}

// Allows us to switch it off later.
#define DEBUG_MEMORY
const int MAXLOCS = 256;

// Here is the actual storage for the data. 
int memUsage = 0;
int memLocs[MAXLOCS];
int memSizes[MAXLOCS];

#ifdef DEBUG_MEMORY
// Overridden new/delete so we can track memory usage.
void* operator new (size_t size)
{
    // First time call handling.
    if (memUsage == 0)
    {
        for (int x = 0; x < MAXLOCS; x++)
        {
            memLocs[x] = 0;
            memSizes[x] = 0;
        }
    }
 
    // Do the actual allocation.
    void *p=malloc(size); 

 
    // Memory counting.
    memUsage += size;

 
    // Pointer tracking. 
    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)
{
    // Handy trap to have.
    if (p == NULL) throw std::bad_alloc();
    
    // Find the pointer and count the memory.
    for (int x = 0; x < MAXLOCS; x++)
    {
        if (memLocs[x] == (int) p)
        {
            memUsage -= memSizes[x];
            memLocs[x] = 0;
            memSizes[x] = 0;
            x = MAXLOCS;
        }
    }
 
    // Actually free the memory.    
    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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)