UC3M

Telematic/Audiovisual Syst./Communication Syst. Engineering

Systems Architecture

September 2017 - January 2018

6.10.2.  The Memory Leak

One of the most common anomalies when managing memory explicitly is what is known as a memory leak. This situation appears when a program obtains a portion of dynamic memory and the value of the pointer returned by the system, by mistake, is lost. In that case, it is no longer possible to invoke the free function to liberate that memory portion and therefore is reserved for the remaining of the execution. As an example of a memory leak, let us analyze the following code fragment.

char *string;
  string = (char *)malloc(100);
  string = NULL;

The first line declares a pointer to char. In the second line a space of 100 bytes is reserved. The memory manager returns a pointer to the beginning of that block and it is stored in the string variable. At this point, the address of this block is not stored anywhere else. The following line assigns the value NULL to the same pointer. What happened with the address of the memory just reserved? It has been lost and there is no way to recover it because string was the only copy of such value. As a consequence, the memory portion will be kept as reserved for the rest of the program execution. The memory leaked.

The main consequence of a memory leak is that the memory portion cannot be reused (it is lost). This is equivalent to a reduction in the amount of available memory for the program execution. The effects of a memory leak depend on the location in the code where they are produced. If a program has a single leak of a few bytes, the effect will very likely go unnoticed. However, if the memory loss is produced in a location in the code that is executed repeatedly, the effect can be catastrophic. Consider the following code fragment:

#define MILLION 1000000

char *table[MILLION];
for (i = 0; i < MILLION; i++) {
  table[i] = (char *)malloc(100);
  table[i] = NULL;
}

The memory leaks in a location that is part of a loop executed one million times. Thus, in the loop, almost 100 megabytes of memory are leaked.

Memory leaks typically happen in situations much more difficult to detect than the trivial ones shown here. They are typically in unexpected locations in the code and are due to errors when manipulating pointers. The memory leak problem in C is so complex that several commercial as well as open source tools have appeared specially conceived to analyze a program and detect them.

A typical memory leak situation is when manipulating chained data structures. In a data structure several pointers obtained through malloc are stored, and inside their memory, other pointers identically obtained are stored. The deallocation of the memory occupied by these data structures must be programmed with extreme care. The following code fragment illustrates this problem.

struct contact_information 
{
  char *name, *lastname;
  int age;
};

struct contact_information *agenda;
int i;

agenda = (struct contact_information *)calloc(100, sizeof(struct contact_information));
for (i = 0; i < 100; i++) {
  agenda[i].name = (char *)malloc(10);
  agenda[i].lastname = (char *)malloc(30);
  agenda.age = 0;
}
free(agenda);

Variable agenda is reserved with space to store 100 structures of type struct contact_information. In the loop, the two first fields of each structure are initialized with two pointers obtained through malloc. After the loop the call free(agenda) deallocates the space reserved for the table, but not the one reserved for the strings in each of its elements. The correct way to free the structure is also looping through all its elements and deallocated each field separately with its own call to free.

The two rules to observe for any C program related to dynamic memory management are:

  1. Any memory portion dynamically reserved (with malloc, calloc or realloc) must be deallocated through a call to free.

  2. If a program executes its last instruction and has dynamic memory blocks not deallocated, the program is considered incorrect.

Unfortunately, there no concrete technique to avoid memory leaks, but there are tools that given a program, analyze the execution and produce a report with the memory that leaked (if any). To give you an idea of the difficulty of this problem, when these tools started to appear, they were used to analyze applications that were considered solid and mature. Surprisingly, several memory leaks were detected and they were not noticed by any programmer in the development team.