A memory leak, in computer science (or leakage, in this context), occurs when a computer program consumes memory but is unable to release it back to the operating system. A memory leak has symptoms similar to a number of other problems (see below) and generally can only be diagnosed by a programmer with access to the program source code; however, many people refer to any unwanted increase in memory usage as a memory leak, though this is not strictly accurate.
A memory leak can diminish the performance of the computer by reducing the amount of available memory. Eventually, in the worst case, too much of the available memory may become allocated and all or part of the system or device stops working correctly, the application fails, or the system slows down unacceptably due to thrashing.
Memory leaks may not be serious or even detectable by normal means. In modern operating systems, normal memory used by an application is released when the application terminates. This means that a memory leak in a program that only runs for a short time may not be noticed and is rarely serious.
Leaks that are much more serious include:
- where the program runs for an extended time and consumes additional memory over time, such as background tasks on servers, but especially in embedded devices which may be left running for many years.
- where new memory is allocated frequently, such as when rendering the frames of a computer game or animated video.
- where the program is able to request memory — such as shared memory — that is not released, even when the program terminates.
- where the leak occurs within the operating system.
- where the leak is the responsibility of a system device driver.
- where memory is very limited, such as in an embedded system or portable device.
- where running on operating systems where memory may not be automatically released on termination, and if lost can only be reclaimed by a reboot (such as AmigaOS).
An example of memory leak
The following example, written in pseudocode, is intended to show how a memory leak can come about, and its effects, without needing any programming knowledge. The program in this case is part of some very simple software designed to control an elevator. This part of the program is run whenever anyone inside the elevator presses the button for a floor.
When a button is pressed:
Get some memory, which will be used to remember the floor number
Put the floor number into the memory
Are we already on the target floor?
If so, we have nothing to do: finished
Wait until the lift is idle
Go to the required floor
Release the memory we used to remember the floor number
The memory leak would occur if the floor number requested is the same floor that the lift is on; the condition for releasing the memory would be skipped. Each time this case occurs, more memory is leaked.
Cases like this wouldn't usually have any immediate effects. People do not often press the button for the floor they are already on, and in any case, the lift might have enough spare memory that this could happen hundreds or thousands of times. However, the lift will eventually run out of memory. This could take months or years, so it might not be discovered by thorough testing.
The consequences would be unpleasant; at the very least, the lift would stop responding to requests to move to another floor. If other parts of the program need memory — a part assigned to open and close the door, for example —, then someone may be trapped inside, since the software cannot open the door.
The memory leak lasts until the system is reset. For example: if the lift's power were turned off the program would stop running. When power was turned on again, the program would restart and all the memory would be available again, but the slow process of memory leak would restart together with the program, eventually prejudicing the correct running of the system.
 Programming issues
Memory leaks are a common error in programming, especially when using languages that have no built-in automatic garbage collection, such as C and C++. Typically, a memory leak occurs because dynamically allocated memory has become unreachable. The prevalence of memory leak bugs has led to the development of a number of debugging tools to detect unreachable memory. IBM Rational Purify, BoundsChecker, Valgrind, Insure++ and memwatch are some of the more popular memory debuggers for C and C++ programs. "Conservative" garbage collection capabilities can be added to any programming language that lacks it as a built-in feature, and libraries for doing this are available for C and C++ programs. A conservative collector finds and reclaims most, but not all, unreachable memory.
Although the memory manager can recover unreachable memory, it cannot free memory that is still reachable and therefore potentially still useful. Modern memory managers therefore provide techniques for programmers to semantically mark memory with varying levels of usefulness, which correspond to varying levels of reachability. The memory manager does not free an object that is strongly reachable. An object is strongly reachable if it is reachable either directly by a strong reference or indirectly by a chain of strong references. (A strong reference is a reference that, unlike a weak reference, prevents an object from being garbage collected.) To prevent this, the developer is responsible for cleaning up references after use, typically by setting the reference to null once it is no longer needed and, if necessary, by deregistering any event listeners that maintain strong references to the object.
In general, automatic memory management is more robust and convenient for developers, as they don't need to implement freeing routines or worry about the sequence in which cleanup is performed or be concerned about whether or not an object is still referenced. It is easier for a programmer to know when a reference is no longer needed than to know when an object is no longer referenced. However, automatic memory management can impose a performance overhead, and it does not eliminate all of the programming errors that cause memory leaks.
RAII, short for Resource Acquisition Is Initialization, is an approach to the problem commonly taken in C++, D, and Ada. It involves associating scoped objects with the acquired resources, and automatically releasing the resources once the objects are out of scope. Unlike garbage collection, RAII has the advantage of knowing when objects exist and when not. Compare the following C and C++ examples:
/* C version */
void f(int n)
int* array = calloc(n, sizeof(int));
// C++ version
void f(int n)
std::vector<int> array (n);
The C version, as implemented in the example, requires explicit deallocation; the array is allocated from the heap, and continues to exist until explicitly freed.
The C++ version requires no explicit deallocation; it will always occur automatically as soon as the object
array goes out of scope, including if an exception is thrown. This avoids the overhead of garbage collection schemes, and can even be applied to resources other than memory such as:
- file handles, which mark-and-sweep garbage collection does not handle as gracefully
- windows that have to be closed
- icons in the notification area that have to be hidden
- synchronisation primitives like monitors, critical sections, etc. which must be released to allow other threads to obtain them
- Windows registry handles that are open
- network connections
- Windows GDI objects
- Actions to perform when a function (or code block) finishes, at any possible point (the action is done by the destructor of an object created when the function starts)
However, using RAII correctly is not always easy and has its own pitfalls. For instance, if one is not careful, it is possible to create dangling pointers (or references) by returning data by reference, only to have that data be deleted when its containing object goes out of scope.
Full article ▸