Share via


Memory Leak Detector - _CrtDumpMemoryLeaks() not showing the line number in file

Question

Wednesday, June 6, 2012 8:36 PM

Hi,

I am trying to detect memory leaks in my application and came across the MSDN link for CrtDumpMemoryLeaks(). I followed all the steps mentioned in the link http://msdn.microsoft.com/en-us/library/x98tx3cf.aspx.However, the debug output only shows the non #define _CRTDBG_MAP_ALLOC version even though I have the same format & same order as defined in the MSDN article. My .cpp file contains the header as stated below:

#include <Windows.h>
#include <stdio.h>
#include .....
#include ....
#define _CRTDBG_MAPALLOC
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <ctime>

However, my output window running the debug exe shows only the raw data and not the file name and line number. Any idea as how to get this fixed so I can see the file name and line number in the output. Below is a snippet of my output. Thanks in advance for the help.

Detected memory leaks!
Dumping objects ->
{152} normal block at 0x00780E80, 400000 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

All replies (10)

Wednesday, June 6, 2012 8:51 PM ✅Answered

Try this...

http://support.microsoft.com/kb/140858


Thursday, June 7, 2012 5:02 AM ✅Answered

>I followed all the steps mentioned in the link
>http://msdn.microsoft.com/en-us/library/x98tx3cf.aspx

All of them? Including this?

"These techniques work for memory allocated using the
standard CRT malloc function. If your program allocates
memory using the C++ new operator, however, you need to
redefine new if you want to see the file and line numbers
in the memory-leak report. You can do that with a block
of code that looks like this: ..."

  • Wayne

Thursday, May 30, 2013 3:33 AM

Hi,

I've had exactly the same issue that MannuK reports ... not getting line numbers reported, just hexadecimal block numbers. I've implemented the #define for new to DEBUG_NEW, Visual Leak Detector and I'm at a complete stand still trying to find the source of the leak. Is there an alternative method for getting MSVS 2010 to provide a mapping of block numbers to source code line numbers?

In parallel, I'm in the process of trying to get corporate funding for Rational Purify - the free/trial version (after spending 2 hours trying to get it to work - it reports that it found leaks, but won't tell me where they are until I buy it) ... so it might do the trick, after I purchase it. I'm also trying to move the code over to Linux to try and use Valgrind ...

Doug


Thursday, May 30, 2013 4:27 AM

I've had exactly the same issue that MannuK reports ... not getting line numbers reported, just hexadecimal block numbers. I've implemented the #define for new to DEBUG_NEW

Where are the memory leaks occurring? In your own code or
in library code?

Can you narrow the source to a probable section of your code?
(By process of elimination.)

To ensure that you are using DBG_NEW correctly, have you
introduced a deliberate leak into your program and checked
to see if *it* shows the line number(s)?

Have you tried it using _CLIENT_BLOCK instead of _NORMAL_BLOCK ?

Have you tried Cppcheck?

http://cppcheck.sourceforge.net/

"Looking for memory leaks and resource leaks is a
key feature of Cppcheck."

  • Wayne

Thursday, May 30, 2013 11:55 PM

Wayne,

Many thanks for the response!! That specific tool I haven't tried yet. Thanks for the suggestion, I'll try it.

Like I mentioned, what I have been doing is getting approval to put Valgrind on a Linux system I have access to ... to see if that finds the issue, while simultaneously trying to purchase PurifyPlus.

I'm using Qt 4.8.4 (long story - but I'm eagerly waiting for Qt's newer 5.1 and 5.2 versions which will provide better OpenGL support) to implement a streaming image viewer that loads them in a thread and then uses Qt's signal/slot mechanism to send them to the primary application for display. My goal is to build a real time OpenGL/CUDA image processing app that allows a number of image processing algorithms to be displayed as the images are displayed in Qt's DockWidgets.

I have conditional compilation wrapping -- one to use Qt's QLabel's to display the images in the Qwidgets ... and when I compile it that way ... no memory leaks. When I use the other conditional compilation to use Qt's OpenGL widgets and OpenGL functions ... I have memory leaks. Only real difference in the code that leaks and doesn't leak is how the images are loaded into graphics memory, and the use of Qt's QGLWidgets... so I suspect the leak is down in that code, but can't prove it yet.

The Visual Leak Detector tool tells me it finds only one memory leak (the image loading thread pointer) ... but I deallocate it using a signal/slot on shut down in the class's destructor ... so that is a false positive. And MSVS's stuff won't give me the line numbers .. I did try moving the lines

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

up to the top of my list of #includes, but then one of my included library's balked at getting recompiled.

So ... let me try Cppcheck, and will see what it finds.

Will keep you posted!!


Friday, May 31, 2013 12:24 AM

Wayne - Okay ... I just finished downloading and running it against my code ... and I get

1 performance suggestion to make a function static,

1 style suggestion to make another function const, and

2 skipped configurations on GL_INVALID flags ... GL_INVALID_FRAMEBUFFER_OPERATION_EXT AND GL_INVALID_INDEX ... that's it...

so nothing I'm doing that it can find...


Friday, May 31, 2013 8:53 AM

I don't see an answer to my question:

"To ensure that you are using DBG_NEW correctly, have you
introduced a deliberate leak into your program and checked
to see if *it* shows the line number(s)?"

I also don't see an answer to my question:

"Have you tried it using _CLIENT_BLOCK instead of _NORMAL_BLOCK ?"

I usually don't post rhetorical questions.

It sounds like the complexity of the program structure renders
it virtually impossible for anyone who doesn't have the code
to offer any advice other than general suggestions.

Some things to keep in mind:

(1) Some leaks are innocuous. An allocation made when the
program starts which is held throughout the program's
lifetime and never released does no harm. The memory is
reclaimed by the OS when the program ends. It's only
repetitive allocations of an object without releasing
any of them while the program runs that leads to a
critical leak.

(2) Using _CrtDumpMemoryLeaks() to report leaks may report
a leak for an object which will actually be freed/deleted
at some point after this report. For example:

A class which allocates in its ctor and deallocates in its
dtor. A local object created on the stack will not be
destroyed - and the dtor called - until it goes out of
scope. If such an object is created for example at the
start of main() and _CrtDumpMemoryLeaks() is called
just before the return from main then the report will
be generated before the object gets destroyed. Wrapping
all code in main in extraneous parentheses and putting
the _CrtDumpMemoryLeaks() after this code block will
cause the destruction of such a local static object
and the "leak" will no longer be reported.

Similarly, an object of such a class which is created as a
global variable will not get destroyed until *after* the
main function is exited. So using _CrtDumpMemoryLeaks()
will always report a leak for the global object even though
none actually exists. This can be avoided by using
_CRTDBG_LEAK_CHECK_DF with _CrtSetDbgFlag() instead of
_CrtDumpMemoryLeaks() to generate the leak report after
program execution ends and cleanup of globals has been
done.

  • Wayne

Friday, May 31, 2013 3:55 PM

Hi Wayne ...

My appologies, I thought my response covered all of the questions you asked ... I know that my implementation of DBG_NEW is working correctly for the following reason:

I create my image loading thread using new in the class constructor, and it only gets called once (I verified this allready) ... the thread isn't deleted until the program exits - where it is delete in the class's destructor.

DBG_NEW properly identifies and prints the file line number information into the Output window for that pointer - but doesn't do that for anything other than new.

I'm in the process of running Valgrind on a Linux system now against a ported version of my code. It is reporting numerous issues inside of Qt's libraries ... so I need to weed through them to see which are legit. I've been fairly careful using Qt's functionality in the same manner as their examples demonstrate, so I'm currently about 80% sure the issue is down in that code some place ... was going to try to upgrade to 5.0 and possibly 5.1 beta which just became available.

I'll also try your other suggestions when I get home.

Thx again for your time!! Doug


Friday, May 31, 2013 5:14 PM

>DBG_NEW properly identifies and prints the file line number
>information into the Output window for that pointer - but
>doesn't do that for anything other than new.

Well, perhaps to belabour the obvious: using the defines
to alter new calls so that the line number and file name
are shown only alters the source code in the compilation
unit in which the defines exist. Any new allocations in
other compilation units or in lib functions will not be
affected by these preprocessor directives. Neither will
any new calls which occur before the define statements.

  • Wayne

Friday, May 31, 2013 10:53 PM

Wayne ... yah, understood...

Sorry though, when I tried to answer your question from work this website blocked my response for some reason, and I see it is now posted. The code I implemented to replace new is

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )      

#define new DBG_NEW   

were correct.

Nothing I've run against my code has identified anything I'm doing that could be the culprit for megabytes of memory getting chewed up.

So ... today using Valgrind on Linux it identified "gobs" (that's a technical term ;-) ) of memory leaking down inside of NVIDIA's OpenGL drivers from a malloc, and minor amounts in some of the Qt code. So doing some Google searches I found the following two other reports of memory leaks implicating OpenGL's glTexSubImage2D and texture loading functionality ...

www.opengl.org/discussion_boards/showthread.php/181618-Memory-leak-using-glTexSubImage2D

and

www.opengl.org/discussion_boards/showthread.php/181771-Memory-leak-while-uploading-textures

I had our sys admin update the NVIDIA drivers there, and I still had the problem - I also use NVIDIA here ... so ... not yet a smoking gun, but darn close. I'll instrument heap dumps around the potential offending functions this evening and tomorrow to verify it. Then I'll move to plan B on my implementation... and use CUDA's memcpy to move the bits to the GPU.

Thx for the help!! Doug

UPDATE:

Being pernicious... and wanting to get to root cause ... what I did was add the following to my code and did a binary search to find the exact call that was the culprit.

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

and then I sprinkled ...

  MEMORYSTATUSEX s1;
  s1.dwLength = sizeof (s1);
  GlobalMemoryStatusEx(&s1);

some OpenGL and QGLWidget calls,

  MEMORYSTATUSEX s2;
  s2.dwLength = sizeof (s2);
  GlobalMemoryStatusEx(&s2);

etc...,

I then streamed the available memory into a file using,

  fs.open ("debug.txt", std::fstream::out | std::fstream::app);
  fs  << "GLWidget::paintGL()  : s1 - Phys    = " << s1.ullAvailPhys/1024 << "\n";
  fs  << "GLWidget::paintGL()  : s1 - Virtual = " << s1.ullAvailVirtual/1024 << "\n";
  fs  << "GLWidget::paintGL()  : s2 - Phys    = " << s2.ullAvailPhys/1024 << "\n";
  fs  << "GLWidget::paintGL()  : s2 - Virtual = " << s2.ullAvailVirtual/1024 << "\n";
  fs.close();

The offending call was a Qt call bindTexture() with the image as the argument. It apparently returns a "texture ID" that needed to be deleted. So I placed a call to deleteTexture("texture ID") after my call to updateGL().

In short ... problem solved!!

I suspect the issue with not seeing the line numbers from the _CrtDumpMemoryLeaks() has to do with the length of the call stack. I saw line numbers on other allocations and deallocations.