2

Memory leaks are a nightmare. I know: I have some.

What is the most effective (least painful and time consuming) way to locate them?

I use Visual Studio 2010 and develop in C++ for Windows.

Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
Bunkai.Satori
  • 4,698
  • 13
  • 49
  • 77
  • Depending on what you're programming, smarter implementation of algotihms etc. can prevent a bunch of problems. It's better to prevent beforehand than allocating them afterhand, in my opinion. – pimvdb Jan 27 '11 at 17:31
  • 4
    I think he meant `locate`, not `allocate` :D – Elalfer Jan 27 '11 at 17:33
  • @Elalfer, my apologies for "allocate". I meant "locate" :-) @Michael Petrotta, thanks for modifications in my question. – Bunkai.Satori Jan 27 '11 at 17:48

8 Answers8

4

Smart Pointers is probably what you are looking for. At least when allocating objects.

For containers, use the STL where possible.

If you are looking for existing memory leaks, you can use DEBUG_NEW if you are in VS2010.

James
  • 5,355
  • 2
  • 18
  • 30
4

I've used Valgrind for Linux, but you can find few useful links here Is there a good Valgrind substitute for Windows?

Community
  • 1
  • 1
Elalfer
  • 5,312
  • 20
  • 25
2

if your code currently has a lot of calls to new and delete, and you can use boost (or tr1), the following types will be immensely helpful in fighting leaks

  • boost::shared_ptr
  • boost::scoped_ptr
  • boost::shared_array
  • boost::scoped_array

replace boost with std::tr1 if you are unable to use boost. More documentation is available on the boost website.

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
2

for MSVC I use following technique:

  1. use precompiled headers (e.g. stdafx.h) at the very beginning of stdafx.h put:

    #if defined(_WIN32) && defined(_DEBUG) && defined(_MSC_VER)
        #define _CRTDBG_MAP_ALLOC
        #include <crtdbg.h>
        #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__)
    #endif
    
  2. then include all headers you aren't going to modify (or very rarely at least). the point here is to include headers with overloaded operator new

  3. at the end of stdafx.h put:

    #if defined(_WIN32) && defined(_DEBUG) && defined(_MSC_VER)
        #if defined(new)
            #undef new
        #endif
        #define new DEBUG_NEW
    #endif
    
  4. in your main() put

    _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
    

    as the first line.

test:

int main()
{
    _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF/* | _CRTDBG_CHECK_CRT_DF*/);
     int* i = new int();
     std::vector<int>* v =  new std::vector<int>(1000);
     return 0;
}

run this under debugger. at VC output window you'll find something like:

The thread 'Win32 Thread' (0x1b1c) has exited with code 0 (0x0).
Detected memory leaks!
Dumping objects ->
{97} normal block at 0x02725E38, 4000 bytes long.
 Data: <                > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
c:\main.cpp(7) : {96} normal block at 0x02725DE8, 20 bytes long.
 Data: <        8^r  mr > 00 00 00 00 CD CD CD CD 38 5E 72 02 D8 6D 72 02 
c:\main.cpp(6) : {95} normal block at 0x02725DA8, 4 bytes long.
 Data: <    > 00 00 00 00 
Object dump complete.
The program '[3756] test.exe: Native' has exited with code 0 (0x0).

as you can see, there're 3 memleaks: two in main() and one somewhere else. "somewhere else" is not detected because it's in <vector> and it was included before our #define new DEBUG_NEW. this report is convenient enough because after every run in debugger you see if new memleaks appeared, and you can just doubl click on corresponding memleak to go to exact place in the editor. {97}, {96} etc. numbers in the example indicate the sequence number of memory allocation, you can use it to trigger corresponding memory allocation by putting _CrtSetBreakAlloc(memalloc_seq_no); before this allocation actually happens.

the technique is far from be perfect and universal, but I found it very useful in everyday programming in VC.

more info in MSDN

Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112
  • +1 Hi Andy, very nice soultion indeed. It twould be nice, if we can be informed about every memory leak, including the one in . – Bunkai.Satori Jan 27 '11 at 18:21
  • you are informed, just w/o filename:lineno info. actuall you rarely need this because `` doesn't have memleaks, it's our code does. as I pointed, the limitation is that you have to include files with declared `operator new` before `#define new DEBUG_NEW`. in special cases you can use `_CrtSetBreakAlloc` to find exact place of mem allocation – Andriy Tylychko Jan 27 '11 at 18:32
  • Andy, yes, you are correct that is designed not to generate any memory leaks. – Bunkai.Satori Jan 27 '11 at 20:57
  • Hi Andy, your answer is very helpful. Aren't you getting *Debug Error: R6010 -abort() has been called* after calling **delete** on dynamically allocated object? – Bunkai.Satori Mar 03 '11 at 23:16
  • @Bunkai: no, I've never seen it. Did you check that this error is related with CRT Debug Heap? (e.g. but commenting out all described things) – Andriy Tylychko Mar 05 '11 at 20:40
  • For C++... also see [MS KB 140670](http://support.microsoft.com/kb/140670) and [Memory leaks reported by debug CRT inside typeinfo.name()](https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=106937). Microsoft has not fixed it in over a decade. Microsoft bugs will mask your bugs, or you will waste hours on Microsoft bugs. Its incredibly irresponsible/negligent/grossly negligent of Microsoft. Here's how you can tell: if a leak is the prefix of a namespace and reported as number ***`N`***, then there will be a ***`N+1`*** leak that immediately follows. – jww Oct 02 '16 at 06:32
2

Before going the debug road, let's us consider the design.

There are two cardinal rules to avoid memory leaks:

  1. don't use new
  2. don't use delete

This might seem surprising at first :)

1. Don't use new

You should not allocate on the heap whenever you can actually avoid it:

  • allocate on the stack
  • use containers that will handle the memory allocations for you

Each new you remove from your code, is necessarily a memory leak you won't have.

2. Don't use delete

The problem is that matching each new with a delete is extremely difficult. It's difficult to remember to delete it, it's difficult not to delete it twice.

C++ offers a handy solution in the form of SBRM (Scoped-Bound Resources Management, also know by the RAII acronym whose name is rather misleading). This notably means smart managers.

Whenever you actually call new, make sure to immediately pass on the responsability of managing the newly allocated object to either a smart pointer, or some other equally smart container (like boost::ptr_vector for example).

3. Code reviews

  • Question every use of new
  • Make sure that every new result is immediately placed within a smart manager

Note: the only place for delete is when YOU are writing a smart manager. There is normally little point in doing so, given the wide selection available. If you do, however, remember that it's guru area (exception safety, ...); the one advice I can give, is that a smart manager does only one thing: it manages smartly a SINGLE resource. Try to combine it with something else, and you'll fail, and you'll not even realize it

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • +1 Hi Matthieu, thanks for your useful advices. I wish I could avoid using *new*, *delete* as I take input from an external files that defines how many objects I have to create. If I haven't used smart pointers so far in my project, it will take a lot of refactoring to implement them in the middle of the project, is that correct, please? – Bunkai.Satori Jan 27 '11 at 21:10
  • @Bunkai: It depends if there is a clear ownership for each object or not, but it might take some time yes. On the other hand... correctness is priceless, isn't it ;) ? – Matthieu M. Jan 28 '11 at 07:04
1

I'm going through my program and reducing the use of smart pointers, as well as singletons.

The idea is to use pointers and smart pointers only when necessary.

I have cleaned up a lot of memory leaks by using these two techniques. For example, if a class needs access to a singleton, convert the singleton to a regular object and pass as an argument. This has as side effect of showing the true requirements of the methods and class rather than having hidden singleton requirements.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • if I understand correctly, using smart pointers is not the best soluion to memory leaks? According to you, is using memory leaks reports a better alternative? – Bunkai.Satori Jan 27 '11 at 18:24
  • @Bunkai, let me clarify. Without any dynamic objects there can be no memory leaks. Each allocation of a dynamic object has potential for a memory leak. Smart pointers reduce the potential for leaks. Smart pointers are a better solution that regular (dumb) pointers. Prefer local, stack allocation to dynamic allocation. Prefer pass by reference to pass by pointer. Prefer smart pointers to regular pointers. – Thomas Matthews Jan 27 '11 at 20:15
  • thanks for your clarification. I understand. Sometimes, I am affraid, it is rather difficult to go with static memory allocation only. Say, if you have external file, and you generate your objects base on the input from the external file. If you do not know, how many objects you are going to have, you would probably waste a lot of memory, to have memory pool large enough, that it can contain the highest possible number of objects coming from the file. But it is good to adopt practice of prefering static allocation over dynamic. – Bunkai.Satori Jan 27 '11 at 21:05
  • +1 on valuable information about smart pointers, not to use them just everywhere, but only when necessary. – Bunkai.Satori Jan 27 '11 at 21:19
1

If you can reproduce the issue I'd recommend using umdh from the windows debugging tools package. If you turn on user mode stack traces using gflags or application verifier for your executable it can take before and after snapshots of all your memory allocations which can then be used to track them down. You can also attach with windbg and use the !heap -l to list any non referenced allocations and can print them using !heap -p -a .

You could also use static analysis tools like Coverity (not sure if there are any good free alternatives) but it might not catch every situation.

Dan
  • 354
  • 1
  • 4
  • Hi Dan. Thanks, and +1 for the new tools: UMDH and Windbg. I do not know these packages well, but I have intuition, that these are external tools. Therefore, they do not give you source code informaton on where to search for memory leak, is that correct please? Correct me, if I am wrong. From timesaving viewpoint, it is more practical to have information straight from source code with a filename and fileline that generates the memory leaks. – Bunkai.Satori Jan 27 '11 at 21:01
  • I think if you have private symbols setup both tools can give file/lines, but they can definately get you functions and stack traces. I like using these tools because it doesn't require any code modification to use them. The microsoft leakdiag tool can do the same as well as allocations from sources not on the default heap manager, I'm however less familiar with it's use. – Dan Jan 28 '11 at 18:01
0

Good plan for world domination with the memory leaks is to not use heap at all.

Instead of:

class A { A() { m_a = new int; } ~A() { delete m_a; } int *m_a; };

can always use:

class A { int m_a; };

and it's considerably simpler and more convinient.

It also works in other situations, Instead of:

MyObject *create_obj(int a) { 
   switch(a) { 
      case 0: return new MyDerived1; 
      case 1: return new MyDerived2; 
   };
}
int main() { MyObject *o = create_obj(1); o->do_x(); o->do_y(); delete o; }

Could always use this:

class Obj {
   Obj(int a) : a(a) { }
   void do_x() { switch(a) { case 0: ... break; case 1: ... break; }; }
   void do_y() { switch(a) { case 0: ... break; case 1: ... break; }; }
   int a;
}; 
int main() { Obj o(1); o.do_x(); o.do_y(); }

Copying a large data structure from scope to another for stack allocation works like this:

void Collect(MyStorage &s)
{
   MyObject o;
   MyObject2 o2(o);
   MyObject3 o3(o2);
   s.Copy(o3);
}
void f(const MyStorage &s);
int main() { MyStorage s; Collect(s); f(s); }

This way creating large data structure on stack will work fine. The Storage class needs heap.

tp1
  • 288
  • 1
  • 3
  • these are just examples of how to avoid using new. It needs to be a convention to be used while writing the code. Fixing it later is considerably more difficult. – tp1 Jan 27 '11 at 19:48
  • Storing lagre data structures on stack is very painful. – crazylammer Jan 27 '11 at 19:59
  • stack is slightly difficult to use. It helps if you can copy your large data structure from scope to another. Also some issues with sizeof and order of classes in header file, but in the end it'll work just fine. – tp1 Jan 27 '11 at 20:17
  • Hi Tp1, thank you for your answer. I agree that static memory allocation is more convenient way, although sometimes it is difficult to estimate how many objects I will have to create. To allocate statically, I would have to create really large memory pools that can cover the maximum number of objects. For mobile applications, there is not usually too much memory to vaste. – Bunkai.Satori Jan 27 '11 at 21:15
  • well, added benefit of stack allocation is that you can know after testing it that it's not possible to run out of stack space any longer. There is upper limit of how much memory you can allocate via stack that can be calculated on compile time. If your data size changes on runtime, you can't put it to stack completely, but instead need to use things like std::vector where actual elements are in heap. – tp1 Jan 27 '11 at 21:45
  • yeah, I see what you mean. using std::vector is nice way on how to avoid memory leaks as it has internal way of releasing allocated memory. – Bunkai.Satori Jan 27 '11 at 21:51