A memory leak occurs when a piece of dynamically allocated memory cannot be freed because the program no longer contains any pointers that point to the block. A simple example of this behavior can be seen by running the corrected “Hello world” program (see Pointer Abuse) with the following arguments:
hello this is a test
If we examine the state of the program at line 28, just before executing the assignment statement for the second time, we observe:
- The variable
string_so_far
points to the string“hello”
that it was assigned as a result of the previous loop iteration. - The variable
string
points to the extended string“hello this”
that was assigned on this loop iteration.
These assignments are shown schematically below; both variables point to blocks of dynamically allocated memory.
Pointer assignment before memory leak
h | e | l | l | o | t | h | i | s |
|
string ↑
h | e | l | l | o |
|
string_so_far ↑
The next statement, string_so_far = string;,
will make both variables point to the longer memery block.
Pointer assignment after the memory leak
h | e | l | l | o | t | h | i | s |
|
string ↑ string_so_far ↑
h | e | l | l | o |
|
Once this happens, however, there is no remaining pointer that points to the shorter block. There is no way the memory that was previously pointed to by string_so_far
can be reclaimed; it is permanently allocated. This is known as a “memory leak” and is diagnosed by Insure++ as shown below.
[hello3.c:28] **LEAK_ASSIGN** >> string_so_far = string; Memory leaked due to pointer reassignment: string Lost block : 0x0804bd68 thru 0x0804bd6f (8 bytes) string, allocated at hello3.c, 18 malloc() (interface) main() hello3.c, 18 Stack trace where the error occurred: main() hello3.c, 28
This example is called LEAK_ASSIGN by Insure++ because it is caused when a pointer is re-assigned. Other types of leaks that Insure++ detects include:
Leak type | Description |
---|---|
LEAK_FREE | Occurs when you free a block of memory that contains pointers to other memory blocks. If there are no other pointers that point to these secondary blocks then they are permanently lost and will be reported by Insure++. |
LEAK_RETURN | Occurs when a function returns a pointer to an allocated block of memory, but the returned value is ignored in the calling routine. |
LEAK_SCOPE | Occurs when a function contains a local variable that points to a block of memory, but the function returns without saving the pointer in a global variable or passing it back to its caller. |
Insure++ indicates the exact source line on which the problem occurs, which is a key issue in finding and fixing memory leaks. This is an extremely important feature, because although it’s easy to introduce subtle memory leaks into your applications, finding them all is hard. Using Insure++, you can instantly pinpoint the line of source code which caused the leak.
Should Memory Leaks be Fixed?
Whether or not this is a serious problem depends on your application. To get more information on the seriousness of the problem, add the "Insure++ summarize leaks outstanding" option to your .psrc file.
When you run the program again, you will see the same output as before, followed by a summary of all the memory leaks in your code.
MEMORY LEAK SUMMARY =================== 5 outstanding memory references for 78 bytes. Leaks detected during execution ------------------------------- 55 bytes 4 chunks allocated at hello3.c, 18 malloc() (interface) main() hello3.c, 18 Outstanding allocated memory ---------------------------- 23 bytes 1 chunk allocated at hello3.c, 18 malloc() (interface) main() hello3.c, 18
This shows that even this short program lost four different chunks of memory. The total of 78 bytes isn’t very large and you might ignore it in a program this size. If this was a routine in a larger program, it would be a serious problem because every time the routine is called it allocates blocks of memory and loses some. As a result, the program gradually consumes more and more memory and will finally crash when the memory space on the host machine is exhausted.
This type of bug can be extremely hard to detect, because it might take literally days to show up. Insure++ only prints one error message although the summary indicates that four memory leaks occurred. This is because Insure++ normally shows only the first error of any given type at each particular source line. If you wish, you can change this behavior as described in Displaying Repeated Errors.
A dynamically allocated memory block is categorized as a leak if a pointer to that block is lost during program execution. A block is categorized as outstanding memory if a pointer to the block is retained up to program termination, but the block is not freed prior to program termination.
Finding All Memory Leaks
For an even greater degree of detection, we suggest the following algorithm for removing all memory leaks from your code.
- Run your program from Inuse (See Monitoring Memory Leaks). If you see an increase in the heap size as you run the program, you are leaking memory.
- Compile all source code, but not libraries, with Insure++. Clean all leaks that are detected by Insure++.
- Compile everything that makes up your application with Insure++ -- source code and libraries. Clean any leaks detected by Insure++. If you do not have source for any of the libraries, skip this step and proceed to Step 4.
- Examine each outstanding memory reference to determine whether or not it is a leak. If the pointer is passed into a library function, it may be saved. If this is the case, it is not a leak. Once every outstanding memory reference is understood, and those that are leaks are cleared, the program is free of memory leaks.