简体   繁体   中英

Memory leak in C,C++; forgot to do free,delete

We allocate memory in C using malloc and in C++ using new. I know that memory allocated must be freed or given back to OS using free in C and delete in C++. If I forgot to use free/delete after allocating memory, it means there will be memory leak.

Now, my question is, is this memory leak only during the time period of execution of program; or is it permanent leak/loss or is it gained again once I restart the system ? What is the internal process actually ? What does memory leak/loss mean exactly?

I would be very grateful if someone could explain this in detail or provide me with some nice references.

UPDATE 1

After reading some answers, I learnt that memory is given back to OS/system after program terminates, if that is so, why everyone needs to care so much about memory leak, and why preventing memory leak is very important ?

UPDATE 2

So, memory leak should be prevented so that the system doesn't crash due to lack of sufficient memory for allocation purposes ??

UPDATE 3

So, after reading all answers, I realized that memory leak is quiet important issues to prevent system crashes. But, for a beginner like me, how can I be sure if my program is completely free from memory leak. I try to do free,delete if I am using malloc,new but sometimes, it gets messy. Is there any tool or method which I can use to know if my program is doing any memory leak ?

UPDATE 4

After reading answers, I have now understood the importance of memory leak free code, less use of new/delete, more use of STL, learnt new stuffs like RAII,valgrind and good programming practices. Thanks to all :)

It's per-process . Once your process exits, the allocated memory is returned to the OS for use by other processes (new or existing).

To answer your edited question, there's only a finite amount of memory in your machine. So if you have a memory leak, then the major problem is that the memory isn't available for other processes to use. A secondary, but not negligible, effect is that your process image grows, you'll swap to disc and performance will be hit. Finally your program will exhaust all the memory in the system and fail, since it's unable to allocate any memory for itself.

It's arguable that for a small process with a short lifetime, memory leaks are tolerable, since the leaked memory will be small in quantity and short-lived.

Take a look at this resource , for possibly more info than you'll ever need. What we're discussing here is dynamic or heap allocation.

A memory leak simply means that your application fails to release memory it has allocated. Once your program ends, it is up to the OS what happens. Every modern OS will reclaim all memory used by the application, so once your process terminates, it'll get cleaned up.

But C/C++ do not guarantee that the OS does that. It is possible on some platforms that the memory stays lost until you reboot.

So the problem with memory leaks is twofold:

  • one a few platforms the system might have to reboot to reclaim the memory. On most platforms this is a non-isssue, although leaking some other resource types may still cause problems.
  • As long as your program is running, it will allocate memory it never frees, which means it'll use more and more memory. If your program is intended to run for a long time, it may end up using all the available memory on the machine, and subsequently crash.

Many short-running programs actually ignore memory leaks because they know it'll get cleaned up by the OS soon enough. Microsoft's C++ compiler does this, as far as I know. They know that once the compiler is invoked, it runs for a couple of minutes at the most. (and they know it runs on Windows, where the OS does reclaim memory once the process terminates) So it's ok that it leaks some memory here and there.

As for how to avoid memory leaks, don't create them.

You risk leaking memory every time you use new/delete, so don't .

When you need an array of data do this:

std::vector<char> vec(200);

instead of this:

char* arr = new char[200];

The former is just as efficient, but you don't have to explicitly call delete to free it std::vector uses RAII to manage its resources internally. And you should do the same -- either by using ready-made RAII classes like vector , shared_ptr , or almost any other class in the standard library or in Boost, or by writing your own.

As a general rule of thumb, your code should not contain any new/delete calls, except in the constructor/destructor for the class responsible for managing that allocation.

If an object allocates the memory it needs in the constructor, and releases it in the destructor (and handles copying/assignment correctly), then you can simply create a local instance of the class on the stack whenever you need it, and it will not, can not, leak memory.

The key to not leaking memory in C++ is to not call new/delete.

The operating system will track memory and once your program terminates will reclaim all the memory. It just means that your application lost track of some allocated memory.

Note that this might not apply on some operating systems but will be the case on any windows/unix/mac type system

Re: tools to detect memory leak

If you use a Linux based OS for development, you can try using valgrind ( http://valgrind.org/ ) to detect memory leak.

valgrind --leak-check=full ./compiled_binary

If you program was compiled with debug symbols (eg for gcc, include the -g flag), valgrind will also inform your of the exact line of code where the leaked memory was allocated. This will greatly ease the task of tracking and fixing leaks.

Pros: it is free

Cons: AFAIK, it only works on Linux

Update

As seen on http://valgrind.org/info/platforms.html , valgrind is being ported to other OSes (and platforms) include MacOSX, FreeBSD and NetBSD.

Update 2

(slightly off topic but...)

The good thing about using valgrind is that it does a lot more than just checking for memory leaks. See http://valgrind.org/info/tools.html

I configured buildbot to run valgrind (and splint) against all my nightly builds, and that has proven invaluable!

有一些工具可以检测内存泄漏,例如Purify

As a new to C++ programmer, the best advice I could give to you would be to learn how to minimize the number of "new" and "delete" statements you write. If you have the compiler create your objects locally on the stack, it will manage the memory for you, deleting the objects automatically as they go out of scope.

There is a programming idea called Resource Acquisition Is Initialization ( RAII ). What this says is "if you need to allocate memory that needs to be deleted, or make sure that stuff you open gets closed, wrap it in an object that you create on the stack. That way when the object goes out of scope the destructor automatically gets invoked, and you delete your resource in the destructor."

Common memory leaks happen when you write a "new" in the code, but your function exits before you call delete. Sometimes you encounter a "return" statement too early, other times an exception gets thrown and caught after your "delete" statement. Following RAII helps you make sure those accidents don't happen.

It's a memory leak.

Basically what it means is that this memory won't be reclaimed until the process is destroyed.

The problem is when the pointer goes out of scope and you don't free the memory then it is allocated by the process but there is no way of the program knowing that it is out of scope and no longer needed (without using a tool like Valgrind).

This is only a major problem if it happens repeatedly. If it does then the program will keep using more and more memory the longer it runs before eventually crashing. Users will need to restart the application regularly to avoid this happening or it using too many system resources.

Update 1:
If you have a simple app that runs once, does its thing and terminates, then a memory leak isn't so important. Its still a very bad practice and if you're coding style is such that you allow leaks in your code at all, then you will probably put the same leaks into apps where it is important - ones that work for days, weeks or years. We have an app here that leaks, so we restart it every month. Its not an ideal situation.

Update 2:
yes, pretty much. But memory leaks should be prevented simply because they are a bug, and you should never write code with a view that bugs are acceptable.

Update 3:
The best way to prevent memory leaks is not to use malloc/free in the first place. If you're using C++ read up on RAII, use classes and copy the objects about, this will ensure you never have leaks... nearly all the time. If you do have to allocate memory explicitly, then make sure you keep track of it. If that means you need a global object somewhere that you store the pointers, then do so. If it means you have a collection class that stores the pointers, then get one. Never allocate memory to a local variable that you might forget about, might return from a function without going over the free call, might pass to another function to free that doesn't get called. A sense of discipline is needed for this (not much discipline is required), but many people will tell you that that same virtue is required to write good, correct, well designed, bug-free code anyway (and they'd be right - if you've ever seen hacked together code compared to well designed code, you'll be able to see the difference immediately).

Notes:
even using a garbage collected language you will still get memory leaks. People add objects to collections, then forget to remove them, and so the object remains in memory forever. That counts as a leak. Its reasonably common in GC languages to do this as people think the GC will do all the work for them. Again, coding/design discipline is required - know what you're doing will prevent these bugs.

Memory leaks can occur even without using malloc/new. Be aware of overwriting pointer variables that already point to some memory. My biggest ever source of leaks was with MSXML, I'd create a CComPtr of a XML object, then call the method to get an element, passing the object in to the method as a parameter. Unfortunately the class was cast to the internal pointer and the method would just overwrite it with the new pointer, leaving the old data leaked. The moral here is that, if using a smart pointer class, make sure you know what its doing, especially with its cast operator.

Tools:
you don't need to buy Purify if running on Windows. Microsoft offers UMDH which takes snapshots of your memory. Take 2 snapshots and compare them using the tool, and you can see allocations that steadily increase over time without being de-allocated. Its not pretty, but it works.

Several points to add:

  1. Learn to work correctly form the beginning -- free memory, it is very hard to fix bad habit.
  2. Memory is not the unique resource that should be managed or managed using new/delete.

    For example, some object may hold some temporary file that should be deleted on the end. Usually such things are binded to some object, so, if your forget to delete object, you forget to unlink the file and... This resource does not come back even with system restart.

    There lots of other similar resources that binded to objects and managed with new/delete: files, sockets, shared memory, database connections and so on. So, all the techniques you learn to manage memory would help you to manage these other, much limited resources that you would have to use.

The memory will not be lost but it stays allocated and so isn't available for the next allocations your program does. This means that your program consumes more and more memory if it continues to allocate memory without deallocating it. After a while there is non unallocated memory left and the next attempt to allocate new memory will fail so your program does.

This memory is taken from the so-called "heap". Which is local to your program and is completely removed when your program finishes. So the "only" harm your program can do to the other programs running in the system and the OS is that they may also be unable to allocate memory because your program has "eaten up" all. As soon as you terminate your program others should run normally if they hadn't crashed in the meantime because of the allocation problems.

A tool for monitoring memory leaks is to override the new and delete operators. This allows you to maintain a list of memory that has been allocated and not freed. So, if a particular object should have freed all of the memory it is using, this mechanism gives you a way to verify that it really has freed the memory.

Along with Purify, you might try a free alternative: valgrind. The stipulation there is that valgrind is a linux-specific solution.

To answer update 3 there is usually a way to indicate whether your process has any outstanding memory allocations _heapwalk (under Win32) will allow you to step through all your allocations and you can see if there are any outstanding.

Beyond that its probably worth wrapping your malloc/new calls so that you record the file and line number of each allocation when it happens. Then in your overridden delete/free you remove it from the list.

eg (Be warned this is totally untested code so it probably won't work off the bat)

struct MemoryAllocEntry
{
    char* pFile;
    char* pLine;
};

extern std::map< MemoryAllocEntry > g_AllocList;

inline void* MyMemAlloc( size_t size, char* pFile, char* pLine )
{
    MemoryAllocEntry mae;
    void* pRet = malloc( size );
    mae.pFile = pFile;
    mae.pLine = pLine;

    g_AllocList[pRet] = mae;

    return pRet;
}

inline void MyMemFree( void* pPtr )
{
    std::map< MemoryAllocEntry >::iterator iter = g_AllocList.find( pPtr );
    if ( iter != g_AllocList.end() )
    {
         g_AllocList.erase( iter );
    }
    free( pPtr );
}

#ifdef _DEBUG
    #define malloc( x ) MyMemAlloc( (x), __FILE__, __LINE__ )
    #define free( x ) MyMemFree( (x) )
#endif

Then all you need to do is step through g_AllocList to find any outstanding allocations. The above obviously only works for malloc and free but you can make it work for new and delete as well (MFC does it, for example).

In answer to your question, and update 1,:

Not all operating systems support the notion of distinct processes, hence will never automatically clean things up.

For example, an embedded OS like VxWorks (in some configurations) does not support the concept of multiple processes, so even after your task has ended, any memory you failed to deallocate will remain. If that wasn't intended, you will end up with a memory leak.

Moreover, such a platform is probably used on a system which is rarely rebooted and doesn't support swap, so any memory leaks are much more serious than they would be on (for example) a desktop.

The correct way to avoid memory leaks is to do less explicit memory management and rely on containers which manage stuff for you, for example STL in C++ (relevant parts of it).

Low-level embedded programmers using C often avoid memory leaks by statically allocating everything at startup. C programmers can also use stack allocation with alloca() to avoid possible memory leaks (but they need to understand exactly how it works).

It's the memory assigned to the proccess. You will get it back when you kill the proccess.

Memory leaks typically cause problems for long running programmes; leaks of just a few bytes in unfortunate places such as loops can rapidly expand the memory footprint of your application.

Answering the edit -

If your program is meant to run,. so something and then terminate then no you don't need to be too worried about freeing memory. It's important for programs that run for a while. If your web browser didn't free memory it used to display a page, it would soon use all the memory in your computer.

it's good practice to free memory anyway though, small programs that run once have a habit of being turned into other things and it's a good habit to get into.

当程序在 Windows 中完成时,它不仅释放内存,而且释放所有句柄(如果我错了,请纠正我)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM