How to find memory leak in a C++ code/project?
I am a C++ programmer on the Windows platform. I am 开发者_如何学Pythonusing Visual Studio 2008.
I usually end up in the code with memory leaks.
Normally I find the memory leak by inspecting the code, but it is cumbersome and is not always a good approach.
Since I can't afford a paid memory leak detection tool, I wanted you guys to suggest the best possible ways to avoid memory leaks.
- I want to the know how the programmer can find memory leaks.
- Is there any standard or procedure one should follow to ensure there is no memory leak in the program?
Instructions
Things You'll Need
- Proficiency in C++
- C++ compiler
- Debugger and other investigative software tools
1
Understand the operator basics. The C++ operator new
allocates heap memory. The delete
operator frees heap memory. For every new
, you should use a delete
so that you free the same memory you allocated:
char* str = new char [30]; // Allocate 30 bytes to house a string.
delete [] str; // Clear those 30 bytes and make str point nowhere.
2
Reallocate memory only if you've deleted. In the code below, str
acquires a new address with the second allocation. The first address is lost irretrievably, and so are the 30 bytes that it pointed to. Now they're impossible to free, and you have a memory leak:
char* str = new char [30]; // Give str a memory address.
// delete [] str; // Remove the first comment marking in this line to correct.
str = new char [60]; /* Give str another memory address with
the first one gone forever.*/
delete [] str; // This deletes the 60 bytes, not just the first 30.
3
Watch those pointer assignments. Every dynamic variable (allocated memory on the heap) needs to be associated with a pointer. When a dynamic variable becomes disassociated from its pointer(s), it becomes impossible to erase. Again, this results in a memory leak:
char* str1 = new char [30];
char* str2 = new char [40];
strcpy(str1, "Memory leak");
str2 = str1; // Bad! Now the 40 bytes are impossible to free.
delete [] str2; // This deletes the 30 bytes.
delete [] str1; // Possible access violation. What a disaster!
4
Be careful with local pointers. A pointer you declare in a function is allocated on the stack, but the dynamic variable it points to is allocated on the heap. If you don't delete it, it will persist after the program exits from the function:
void Leak(int x){
char* p = new char [x];
// delete [] p; // Remove the first comment marking to correct.
}
5
Pay attention to the square braces after "delete." Use delete
by itself to free a single object. Use delete []
with square brackets to free a heap array. Don't do something like this:
char* one = new char;
delete [] one; // Wrong
char* many = new char [30];
delete many; // Wrong!
6
If the leak yet allowed - I'm usually seeking it with deleaker (check it here: http://deleaker.com).
You can use some techniques in your code to detect memory leak. The most common and most easy way to detect is, define a macro say, DEBUG_NEW and use it, along with predefined macros like __FILE__
and __LINE__
to locate the memory leak in your code. These predefined macros tell you the file and line number of memory leaks.
DEBUG_NEW is just a MACRO which is usually defined as:
#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW
So that wherever you use new
, it also can keep track of the file and line number which could be used to locate memory leak in your program.
And __FILE__
, __LINE__
are predefined macros which evaluate to the filename and line number respectively where you use them!
Read the following article which explains the technique of using DEBUG_NEW with other interesting macros, very beautifully:
A Cross-Platform Memory Leak Detector
From Wikpedia,
Debug_new refers to a technique in C++ to overload and/or redefine operator new and operator delete in order to intercept the memory allocation and deallocation calls, and thus debug a program for memory usage. It often involves defining a macro named DEBUG_NEW, and makes new become something like new(_FILE_, _LINE_) to record the file/line information on allocation. Microsoft Visual C++ uses this technique in its Microsoft Foundation Classes. There are some ways to extend this method to avoid using macro redefinition while still able to display the file/line information on some platforms. There are many inherent limitations to this method. It applies only to C++, and cannot catch memory leaks by C functions like malloc. However, it can be very simple to use and also very fast, when compared to some more complete memory debugger solutions.
Running "Valgrind" can:
1) Help Identify Memory Leaks - show you how many memory leaks you have, and point out to the lines in the code where the leaked memory was allocated.
2) Point out wrong attempts to free memory (e.g. improper call of delete
)
Instructions for using "Valgrind"
1) Get valgrind here.
2) Compile your code with -g
flag
3) In your shell run:
valgrind --leak-check=yes myprog arg1 arg2
Where "myprog" is your compiled program and arg1
, arg2
your programme's arguments.
4) The result is a list of calls to malloc
/new
that did not have subsequent calls to free delete.
For example:
==4230== at 0x1B977DD0: malloc (vg_replace_malloc.c:136)
==4230== by 0x804990F: main (example.c:6)
Tells you in which line the malloc
(that was not freed) was called.
As Pointed out by others, make sure that for every new
/malloc
call, you have a subsequent delete
/free
call.
There are some well-known programming techniques that will help you to minimize the risk of getting memory leaks at first hand:
- if you have to do your own dynamic memory allocation, write
new
anddelete
always pairwise, and make sure the allocation/deallocation code is called pairwise - avoid dynamic memory allocation if you can. For example, use
vector<T> t
whereever possible instead ofT* t = new T[size]
- use "smart pointers" like boost smart pointers (http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm)
- my personal favorite: make sure you have understood the concept of ownership of a pointer, and make sure that everywhere where you use pointers, you know which code entity is the owner
- learn which constructors / assignment operators are automatically created by the C++ compiler, and what that means if you have class that owns a pointer (or what that means if you have a class that contains a pointer to an object it does not own).
A survey of automatic memory leak checkers
In this answer, I compare several different memory leak checkers in a simple easy to understand memory leak example.
Before anything, see this huge table in the ASan wiki which compares all tools known to man: https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924
The example analyzed will be:
main.c
#include <stdlib.h>
void * my_malloc(size_t n) {
return malloc(n);
}
void leaky(size_t n, int do_leak) {
void *p = my_malloc(n);
if (!do_leak) {
free(p);
}
}
int main(void) {
leaky(0x10, 0);
leaky(0x10, 1);
leaky(0x100, 0);
leaky(0x100, 1);
leaky(0x1000, 0);
leaky(0x1000, 1);
}
GitHub upstream.
We will try to see how clearly do the different tools point us to the leaky calls.
tcmalloc from gperftools by Google
https://github.com/gperftools/gperftools
Usage on Ubuntu 19.04:
sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
HEAPCHECK=normal \
HEAPPROFILE=ble \
./main.out \
;
google-pprof main.out ble.0001.heap --text
The output of the program run contains the memory leak analysis:
WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581d3 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581b5 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
If the preceding stack traces are not enough to find the leaks, try running THIS shell command:
pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --gv
If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks
and the output of google-pprof
contains the heap usage analysis:
Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
0.0 100.0% 100.0% 0.0 100.0% my_malloc
0.0 0.0% 100.0% 0.0 100.0% __libc_start_main
0.0 0.0% 100.0% 0.0 100.0% _start
0.0 0.0% 100.0% 0.0 100.0% leaky
0.0 0.0% 100.0% 0.0 100.0% main
The output points us to two of the three leaks:
Leak of 256 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581d3 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581b5 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
I'm not sure why the third one didn't show up
In any case, when usually when something leaks, it happens a lot of times, and when I used it on a real project, I just ended up being pointed out to the leaking function very easily.
As mentioned on the output itself, this incurs a significant execution slowdown.
Further documentation at:
- https://gperftools.github.io/gperftools/heap_checker.html
- https://gperftools.github.io/gperftools/heapprofile.html
See also: How To Use TCMalloc?
Tested in Ubuntu 19.04, google-perftools 2.5-2.
Address Sanitizer (ASan) also by Google
https://github.com/google/sanitizers
Previously mentioned at: How to find memory leak in a C++ code/project? TODO vs tcmalloc.
This is already integrated into GCC, so you can just do:
gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out
and execution outputs:
=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4096 byte(s) in 1 object(s) allocated from:
#0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
#1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
#2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
#3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
#4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
Direct leak of 256 byte(s) in 1 object(s) allocated from:
#0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
#1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
#2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
#3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
#4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
Direct leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
#1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
#2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
#3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
#4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).
which clearly identifies all leaks. Nice!
ASan can also do other cool checks such as out-of-bounds writes: Stack smashing detected
Tested in Ubuntu 19.04, GCC 8.3.0.
Valgrind
http://www.valgrind.org/
Previously mentioned at: https://stackoverflow.com/a/37661630/895245
Usage:
sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out
Output:
==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178==
==32178==
==32178== HEAP SUMMARY:
==32178== in use at exit: 4,368 bytes in 3 blocks
==32178== total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178==
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178== by 0x10915C: my_malloc (main.c:4)
==32178== by 0x109179: leaky (main.c:8)
==32178== by 0x1091B4: main (main.c:16)
==32178==
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178== by 0x10915C: my_malloc (main.c:4)
==32178== by 0x109179: leaky (main.c:8)
==32178== by 0x1091D2: main (main.c:18)
==32178==
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178== by 0x10915C: my_malloc (main.c:4)
==32178== by 0x109179: leaky (main.c:8)
==32178== by 0x1091F0: main (main.c:20)
==32178==
==32178== LEAK SUMMARY:
==32178== definitely lost: 4,368 bytes in 3 blocks
==32178== indirectly lost: 0 bytes in 0 blocks
==32178== possibly lost: 0 bytes in 0 blocks
==32178== still reachable: 0 bytes in 0 blocks
==32178== suppressed: 0 bytes in 0 blocks
==32178==
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
So once again, all leaks were detected.
See also: How do I use valgrind to find memory leaks?
Tested in Ubuntu 19.04, valgrind 3.14.0.
Valgrind http://valgrind.org/
and
GDB http://www.gnu.org/software/gdb/
- Download Debugging Tools for Windows.
- Use the
gflags
utility to turn on user-mode stack traces. - Use
UMDH
to take multiple snapshots of your program's memory. Take a snapshot before memory gets allocated, and take a second snapshot after a point at which you believe that your program has leaked memory. You might want to add pauses or prompts in your program to give you a chance to runUMDH
and take the snapshots. - Run
UMDH
again, this time in its mode that does a diff between the two snapshots. It will then generate a report containing the call stacks of suspected memory leaks. - Restore your previous
gflags
settings when you're done.
UMDH
will give you more information than the CRT debug heap because it is watching memory allocations across your entire process; it can even tell you if third-party components are leaking.
If you use gcc, there's gprof available.
I wanted to the know how programmer find memory leak
Some uses tools, some does what you do, could also through peer code review
Is there any standard or procedure one should follow to ensure there is no memory leak in the program
For me: whenever I create dynamically allocated objects, I always put the freeing code after, then fill the code between. This would be OK if you're sure there won't be exceptions in the code between. Otherwise, I make use of try-finally (I don't use C++ frequently).
In visual studio, there is a built in detector for memory leak called C Runtime Library. When your program exits after the main function returns, CRT will check the debug heap of your application. if you have any blocks still allocated on the debug heap, then you have memory leak..
This forum discusses a few ways to avoid memory leakage in C/C++..
You can use the tool Valgrind to detect memory leaks.
Also, to find the leak in a particular function, use exit(0) at the end of the function and then run it with Valgrind
`$` valgrind ./your_CPP_program
Search your code for occurrences of new
, and make sure that they all occur within a constructor with a matching delete in a destructor. Make sure that this is the only possibly throwing operation in that constructor. A simple way to do this is to wrap all pointers in std::auto_ptr
, or boost::scoped_ptr
(depending on whether or not you need move semantics). For all future code just ensure that every resource is owned by an object that cleans up the resource in its destructor. If you need move semantics then you can upgrade to a compiler that supports r-value references (VS2010 does I believe) and create move constructors. If you don't want to do that then you can use a variety of tricky techniques involving conscientious usage of swap, or try the Boost.Move library.
AddressSanitizer (ASan) is a fast memory error detector. It finds use-after-free and {heap,stack,global}-buffer overflow bugs in C/C++ programs. It finds:
- Use after free (dangling pointer dereference)
- Heap buffer overflow
- Stack buffer overflow
- Global buffer overflow
- Use after return
- Initialization order bugs
This tool is very fast. The average slowdown of the instrumented program is ~2x.
Answering the second part of your question,
Is there any standard or procedure one should follow to ensure there is no memory leak in the program.
Yes, there is. And this is one of the key differences between C and C++.
In C++, you should never call new
or delete
in your user code. RAII is a very commonly used technique, which pretty much solves the resource management problem. Every resource in your program (a resource is anything that has to be acquired, and then later on, released: file handles, network sockets, database connections, but also plain memory allocations, and in some cases, pairs of API calls (BeginX()/EndX(), LockY(), UnlockY()), should be wrapped in a class, where:
- the constructor acquires the resource (by calling
new
if the resource is a memroy allocation) - the destructor releases the resource,
- copying and assignment is either prevented (by making the copy constructor and assignment operators private), or are implemented to work correctly (for example by cloning the underlying resource)
This class is then instantiated locally, on the stack, or as a class member, and not by calling new
and storing a pointer.
You often don't need to define these classes yourself. The standard library containers behave in this way as well, so that any object stored into a std::vector
gets freed when the vector is destroyed. So again, don't store a pointer into the container (which would require you to call new
and delete
), but rather the object itself (which gives you memory management for free). Likewise, smart pointer classes can be used to easily wrap objects that just have to be allocated with new
, and control their lifetimes.
This means that when the object goes out of scope, it is automatically destroyed, and its resource released and cleaned up.
If you do this consistently throughout your code, you simply won't have any memory leaks. Everything that could get leaked is tied to a destructor which is guaranteed to be called when control leaves the scope in which the object was declared.
Visual Leak Detector (VLD) is a free, robust, open-source memory leak detection system for Visual C++.
When you run your program under the Visual Studio debugger, Visual Leak Detector will output a memory leak report at the end of your debugging session. The leak report includes the full call stack showing how any leaked memory blocks were allocated. Double-click on a line in the call stack to jump to that file and line in the editor window.
If you only have crash dumps, you can use the Windbg !heap -l
command, it will detect leaked heap blocks. Better open the gflags option: “Create user mode stack trace database”, then you will see the memory allocation call stack.
MTuner is a free multi platform memory profiling, leak detection and analysis tool supporting MSVC, GCC and Clang compilers. Features include:
- timeline based history of memory usage and live memory blocks
- powerful memory operation filtering based on heap, memory tag, time range, etc.
- SDK for manual instrumentation with full source code
- continuous integration support through command line usage
- call stack tree and tree map navigation
- much more.
Users can profile any software targeting platforms with GCC or Clang cross compilers. MTuner comes with built in support for Windows, PlayStation 4 and PlayStation 3 platforms.
On Windows you can use CRT debug heap.
Is there any standard or procedure one should follow to ensure there is no memory leak in the program.
Yeah, don't use manual memory management (if you ever call delete
or delete[]
manually, then you're doing it wrong). Use RAII and smart pointers, limit heap allocations to the absolute minimum (most of the time, automatic variables will suffice).
In addition to the tools and methodes provided in the other anwers, static code analysis tools can be used to detect memory leaks (and other issues as well). A free an robust tool is Cppcheck. But there are a lot of other tools available. Wikipedia has a list of static code analysis tools.
Make certain that all the heap memory is successfully freed. There is no need if you never allocate memory on the heap. If you do, count the number of times you malloc memory, and count up the number of time you free memory.
Neither "new" or "delete" should ever be used in application code. Instead, create a new type that uses the manager/worker idiom, in which the manager class allocates and frees memory and forwards all other operations to the worker object.
Unfortunately this is more work than it should be because C++ doesn't have overloading of "operator .". It is even more work in the presence of polymorphism.
But this is worth the effort because you then don't ever have to worry about memory leaks, which means you don't even have to look for them.
精彩评论