Memory Leak Detection in VS

From QtCentreWiki

Jump to:navigation, search

Abstract

This guide shows how to enable memory leak detection inside of a Visual Studio project.

Requirements

You should already have a C++ based Visual Studio project setup and compiling.

Enabling Memory Leak Detection

To enable Visual Studio's built-in memory leak detection, we need to add a few things to our main.cpp file. Adjust accordingly if your program's entry point is in a different location.

After all of your include files, and ONLY in your main.cpp file, add in:

  #if defined(WIN32) && defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
  #endif

To enable memory leak detection in other files you only need to include this before your code in each HEADER file (assuming each .h file has an associated .cpp file):

  #if defined(WIN32) && defined(_DEBUG)
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
  #endif

NOTE: when including either one of the above segments in your files, these must come AFTER prebuilt libraries. Otherwise you will get strange errors as a result of the "new" operator being redefined.

For example, if we were to place this line:

#include <QApplication>

below our #if.... stuff, you'll get strange errors. One potential pitfall that I see people run into quite often is that they often have #include files which have the above memory leak detection in them and then they include that header file before a precompiled header.

This is an example of the way you should not use memory leak detection!

correct.h:

#include <QPushButton>
#include <cstdlib>
  #if defined(WIN32) && defined(_DEBUG)
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
  #endif
...

incorrect.h

#include "correct.h"
#include <QDialog>
#include <fstream>
....

Notice that in the incorrect.h file, we first include the "correct.h" file, which will re-define the new operator. Now when the compiler includes the two pre-compiled headers: QDialog and fstream... errors! The moral here is be aware of what is getting included when.

Printing Leaks to VS Output Console

Now that will enable the memory leak detection, but its really useful to have it print to VS's output console so that we can just double click on the item causing the leak and go right to it. Add in this line directly under your int main() function:

#if defined(_MSC_VER) && defined(_DEBUG)
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

That enables the memory leaks to show up under Visual Studio's output window. Your main.cpp file should now resemble something like:

#include <QApplication>
#include "TestDialogDlg.h"
#if defined(WIN32) && defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
int main(int argc, char *argv[])
{
#if defined(_MSC_VER) && defined(_DEBUG)
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
    QApplication app(argc, argv);
    TestDialogDlg pDlg = new TestDialogDlg();
    return app.exec();
}

The nice thing with the #defines that I'm using is that memory leak detection will only be turned on if you are compiling under Visual Studio AND you are in Debug mode. If you compile in release mode, memory leak detection will not be turned on.

Results

In the main.cpp file segment that I've posted above, clearly we are leaking the pDlg object. So let's take a look at what Visual Studio will show.

1) Build the project in Debug mode
2) Debug the project (press F5)
3) Exit the application normally
4) Memory leaks are now printed in the console view

Here's a screen shot of my setup after running the code: MemoryLeak.jpg You can see that the originating memory leak occurred from line 18 of my file.

One thing to notice from the picture is that there are a lot of memory leaks printing out. This is because there are some font libraries that Qt uses which leak memory. Fear not, its a very small amount that even over large periods of time doesn't amount to any noticeable amount. Furthermore, you can't do anything about them.

One thing to note is that the new operator must be redefined for VS to be able to tell you where in your project a memory leak is occurring. Otherwise you'll just see a leak and it won't tell you where it originated from. So it makes sense why we can't see where pre-compiled libraries are leaking memory. We can't redefine their "new" operators, so we can't detect where their leaks originated from.




Paul 5:26, 21 March 2008 (EST)