Thursday, May 29, 2014

Haunting memory leaks in Visual Studio with DEBUG_NEW

The simplest ever way to find where it leaks.

1. Insert well known piece of code in all .cpp files suspected for leakage:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
2. Use CMemoryState to dump blocks allocated within suspected region:
CMemoryState msOld;
msOld.Checkpoint();
CPerson* pper1 = new CPerson();
CPerson* pper2 = new CPerson();
msOld.DumpAllObjectsSince();
See further how #define DUMP_NEW can help you automate leak searching


First of all look at Output window for example of dump:

Dumping objects ->
{359} normal block at 0x0020B6B0, 52 bytes long.
 Data: <                > B0 B6 20 00 B0 B6 20 00 B0 B6 20 00 CD CD CD CD
c:\dev\channel.cpp(91) : {358} normal block at 0x0020B658, 28 bytes long.
 Data: <                > 00 00 00 00 CD CD CD CD CD CD CD CD CD CD CD CD
{357} normal block at 0x0020B610, 12 bytes long.
 Data: <        H   > 00 B5 20 00 00 B5 20 00 48 B5 20 00
{356} normal block at 0x0020B5A0, 52 bytes long.
 Data: <                > A0 B5 20 00 A0 B5 20 00 A0 B5 20 00 CD CD CD CD
c:\dev\manager.cpp(107) : {355} normal block at 0x0020B548, 28 bytes long.
 Data: <                > 00 00 00 00 CD CD CD CD CD CD CD CD CD CD CD CD
{354} normal block at 0x0020B500, 12 bytes long.
 Data: <            > 10 B6 20 00 10 B6 20 00 CD CD CD CD
c:\dev\manager.cpp(68) : {353} normal block at 0x0020B4A8, 28 bytes long.
 Data: <                > 01 00 00 00 00 00 00 00 CD CD CD CD CD CD CD CD
{352} normal block at 0x0020B438, 52 bytes long.
 Data: <8   8   8       > 38 B4 20 00 38 B4 20 00 38 B4 20 00 CD CD CD CD
Object dump complete.

And after application exits you'll have memory leak report.

Detected memory leaks!
Dumping objects ->
{359} normal block at 0x0020B6B0, 52 bytes long.
 Data: <                > B0 B6 20 00 B0 B6 20 00 B0 B6 20 00 CD CD CD CD
c:\dev-9.2\hyp_src\msghandler\channel.cpp(91) : {358} normal block at 0x0020B658, 28 bytes long.
 Data: <                > 00 00 00 00 CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

But this might not help you locate exact place where it leaks. You might need to insert lots of

msOld.DumpAllObjectsSince();
TRACE0("CMyApp::CMyApp\n")
msOld.Checkpoint();
in every function.
To automate debugging, add this definition at the beginning of .cpp:

#ifdef _DEBUG
#define new DEBUG_NEW

static CMemoryState st_memoryState;
#define DUMP_CONCAT2(x,l,y,z) x## "(" ## # l## "):" ##y## " #" ## #z
#define DUMP_CONCAT1(x,l,y,z) DUMP_CONCAT2(x,l,y,z)
#define __DUMPID__  DUMP_CONCAT1(__FILE__,__LINE__,__FUNCTION__,__COUNTER__)

#define DUMP_NEW_INIT st_memoryState.Checkpoint();
#define DUMP_NEW \
{\
   TRACE0( "########\n" __DUMPID__ "\n");\
   st_memoryState.DumpAllObjectsSince();\
   st_memoryState.Checkpoint();\
}
#else
#define DUMP_NEW_INIT ;
#define DUMP_NEW ;
#endif
and then just insert DUMP_NEW in each check point, having inserted DUMP_NEW_INIT at the very begining

CMyApp::CMyApp()
{
   DUMP_NEW_INIT
}


BOOL CMessageBoxLabApp::InitInstance()
{
   //bla-bla
   DUMP_NEW

   //bla-bla
   DUMP_NEW
   //bla-bla
   DUMP_NEW
}
and then have good looking Output Window:

########
d:\work\messageboxlab\messageboxlab\messageboxlab.cpp(115):CMessageBoxLabApp::CMessageBoxLabApp #0
Dumping objects ->
Object dump complete.
########
d:\work\messageboxlab\messageboxlab\messageboxlab.cpp(146):CMessageBoxLabApp::InitInstance #2
Dumping objects ->
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {569} normal block at 0x007ADD60, 19 bytes long.
 Data: <<Njx            > 3C 4E 6A 78 02 00 00 00 02 00 00 00 01 00 00 00
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {568} normal block at 0x007ADD10, 19 bytes long.
 Data: <<Njx            > 3C 4E 6A 78 02 00 00 00 02 00 00 00 01 00 00 00
Object dump complete.
########
d:\work\messageboxlab\messageboxlab\messageboxlab.cpp(157):CMessageBoxLabApp::InitInstance #3
Dumping objects ->
Object dump complete.
########
d:\work\messageboxlab\messageboxlab\messageboxlab.cpp(161):CMessageBoxLabApp::InitInstance #4
Dumping objects ->
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {580} normal block at 0x007AE2E8, 23 bytes long.
 Data: <<Njx            > 3C 4E 6A 78 06 00 00 00 06 00 00 00 01 00 00 00
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {579} normal block at 0x007AE288, 33 bytes long.
 Data: <<Njx            > 3C 4E 6A 78 10 00 00 00 10 00 00 00 01 00 00 00
{578} normal block at 0x007AE238, 20 bytes long.
 Data: <    PNjxPNjxPNjx> 04 00 00 00 50 4E 6A 78 50 4E 6A 78 50 4E 6A 78
{577} normal block at 0x007AE1D8, 32 bytes long.
 Data: < Y%x    < z   z > FC 59 25 78 04 00 00 00 3C E2 7A 00 98 E2 7A 00
Object dump complete.

Thanks for patience!

No comments:

Post a Comment