views:

339

answers:

6

What are some tips I can use to avoid memory leaks in my applications? In my current project I use a tool "INSURE++" which finds the memory leak and generate the report.

Apart from the tool is there any method to identify memory leaks and overcome it.

+2  A: 

There are three main ways of doing this.

The first is to not create memory leaks in the first place. Defensive programming techniques are invaluable here. See this excellent presentation for a summary of this issues, or the relevant chapter in Secure C Coding. I am more familiar with C than C++, but I understand that C++'s smart pointers are useful here.

A second approach static analysis, which attempts to detect errors in your source-code. The original tool in this category is lint, which is now sadly outdated. The best tools, as far as I know, are commercial such as coverty. However, some free tools do exist.

The third approach is to detect memory leaks at runtime, like INSURE++ does. Valgrind is excellent here and highly recommended. It may help catch bugs you've already introduced. It is especially helpful if you do have a test suite that has good code coverage.

fmark
A: 

To avoid or to detect? To avoid, first detect and try to understand where and why... Another way could be the use of a GC library, like the one described here, but other (maybe better) libraries may exist.

ShinTakezou
+2  A: 

Are we talking tools to find leaks, or ways to code to avoid them?

For the former, the above mentioned valgrind, or Rational suite of IBM tools if you have a license to that. Dr. Dobbs recommended CompuWare’s BoundsChecker but that was 2002.

For the later, see:

http://stackoverflow.com/questions/959621/c-idiom-to-avoid-memory-leaks

http://www.cprogramming.com/tutorial/memory_debugging_parallel_inspector.html

http://scottmcpeak.com/memory-errors/

http://www.yolinux.com/TUTORIALS/C++MemoryCorruptionAndMemoryLeaks.html

DVK
+1  A: 

Use a smart pointer, such as std::shared_ptr<t> (C++0x), std::tr1::shared_ptr<t> (TR1), or boost::shared_ptr<t>. Of course this solution only works with C++ -- you're on your own in C.

Billy ONeal
+2  A: 

Smart pointers can be very helpful in automating the bookkeeping of object lifetimes:

http://ootips.org/yonat/4dev/smart-pointers.html

Where possible, use stack allocated objects inside of their relevant scopes instead of new/delete.

Tools like valgrind have some overhead and can slow down your runs. If you know your codebase and the kinds of leaks that tend to arise, you can target specific classes and implement lighter weight checks (even just a simple object count that you check against zero when you quit). These lightweight checks can then be used to motivate you into doing a more extensive valgrind debugging session when they are triggered.

Hostile Fork
+1  A: 

For C, a good code organization helps. I.e. don't throw calls to malloc() and free() all over your codebase. Centralize them into two functions, then you have one single point for all the checkings. The simplest one could be to count the successful calls and check at program exit that they are balanced.

static unsigned long mymem_count_alloc = 0;
static unsigned long mymem_count_free  = 0;

void *mymem_alloc (size_t size)
{
    void *p;

    p = malloc(size);
    if (p)
    {
        mymem_count_alloc++;
    }
    else
        error logging/handling/signaling

    return (p);
}

void mymem_free (void *p)
{
    if (p)
    {
        free(p);
        mymem_count_free++;
    }
}

void mymem_check (void)
{
    if (mymem_count_alloc != mymem_count_free)
        error alert
}

You can continue this for the different data structures. Whereever you need to allocate memory for a string, use mystr_alloc and mystr_free. And so on. When a leak is detected this way, you can quickly narrow it down.

Secure
+1 mainly for the 'For C, a good code organization helps...'. Personally, I'd prefer to not use this exact method. I'd go for using opaque data structures forcing the use of a functions to create/destroy each particular data type. The counting would shift into these data structures create/destroy functions. You do need to organize your code clearly for this, as it's all to easy for it to get messy. This will be enough to catch many leaks, and valgrind is very good at say catching fence post errors in arrays.
James Morris
Saying that, this method would still be useful, but I'd certainly want it's usage to be conditional: it replaces malloc/free for debug builds, but malloc/free is used in release builds.
James Morris
@James: I go with the create/destroy approach, too. But in there, wrapper functions for malloc/free similar to these are always used, a bit more sophisticated as this example, of course. The error handling part is always necessary, and if something is **always** necessary when calling a library function, then it should either become a part of the function itself or be put into a wrapper if the manipulation of the function is not possible, regarding the DRY principle. http://stackoverflow.com/questions/1529679/how-do-you-program-safely-outside-of-a-managed-code-environment/1530581#1530581
Secure
Saying that (me too ;), what is your reason to make it conditional?
Secure
The basic idea of making it compile conditionally is to remove what in my opinion is debugging code from the release build.
James Morris
If your `mymem_alloc` function does error checking, do you pass the error string? Doesn't the caller still have to check the return value of `mymem_alloc` before proceeding? How do you handle this? Any code online somewhere I can look at please? (This boiler plate stuff is what I'm running into a lot of at the moment...)
James Morris
Yes, the caller has to do error checking, since I don't simply terminate the program on a malloc failure. It is embedded within a more sophisticated error handling scheme. Most of the usual boilerplate code is to set an error number and message and write some logging stuff. This is done within the wrapper, so the caller only has to check that the pointer is not NULL. In the best case it can simply ignore the case when it is NULL, else there is some rollback for error recovery, to leave the function in the program state in which it was entered. Nothing online, sorry.
Secure