Thursday, February 4, 2010

Why Leaking Memory ?

This is a common practice programmers have , including myself not to check for any growth in memory of programs written unless someone asks to.

Here is a definition of Memory Leak.

Memory leak is what happens when a program is unable to release memory allocated by it, back to the OS/kernel.

In simple terms I have borrowed something from a friend of mine and I lost it.Now I cannot return it to him. No, I am not Amir Khan from Ghajni, I still remember who that friend of mine is . Just that I am so much careless that I do not take care of stuffs borrowed from friends.

Now this inability of the program to release the memory back to the kernel, in a long run causes the system memory to be full and hence less memory availability for other process to run hence decrease in system performance and consequently bad days for the developer who did not fix the leak at the right time and so on.Hopefully I am still doing fine after ignoring so many memory leaks :-

So, to avoid all that all we have to do is not waste time on facebook/orkut in office time, not spend time at tea or lunch discussing Kat-Salman relationship , not spend time on cracking stupid PJs at your workplace, but the easiest one will be to read further and get enlightened.

Here I have tried to come up with a list of reasons of Memory Leaks and the possible solution for the same apart from not being drunk while writing a piece of code.

A very simple memory leak can be introduced as follows.
int main()
{

char* ch = new char(100);

//Do not free the pointer ch, using
//delete ch;
//and you get a memory leak

}

This looks harmless but if we put the allocation in a while or a for loop to run indefinitely, it make matters worse.

Here are few scenario I could come up with in which we can get memory leak.

1. Assigning a pointer NULL after allocating memory.
{
char *ch = new char(10);
ch = NULL;
}

Solution is to free the memory allocated before assigning NULL to the pointer.

2. Freeing the memory using a pointer of different data type. Sounds rare but its possible.
{
char* ch = new char(100);
int *num = (int*)ch;
delete num; //Just frees sizeof(int) bytes
}

Solution is to delete the pointer of same type which was used while memory allocation.

3. In case of arrays missing [] with delete operator.
{
char* ch = new char[100];
delete ch; //will free just 1byte
}


Solution is to use [] while freeing memory allocated for arrays.
{
char *ch = new char[100];
delete [] ch; // or delete ch[]
}

4. STL containers do not call delete if pointers are stored. For example
a.
{

vector<char*> list;
list.push_back(new car(10));
list.push_back(new car(100));
list.clear();//Clearing pointers, not freeing memory
}
b.
{
map<int, char*> myMap;
myMap[1] = new char(10);
myMap.clear();//Clearing pointers, not freeing memory
}

Solution will be traverse the map or vector or any such container and free the allocated memory individually and then clear the container.

5. Sometimes it happens that a function allocates and returns the pointer to the calling code, but the calling code does not free the pointer.
a.
void fun(char* * ch)
{
*ch = new char(10);
}
b.
char* fun()
{
char *ch = new char(10);
return ch;
}
c.
There are APIs provided by libraries, that provide documentation about the handling of the pointer deletion.

Solution is to free the pointer responsibly and follow the API documentation.

6. Forgetting to delete the pointer member variable in the destructor.
class A
{
char* ch;
public:
A()
{
ch = new char(100);
}
~A()
{
//ch not deleted, memory leak
//delete ch;
}
}

Solution is to free the memory allocated as follows in the destructor
~A()
{
if(ch != NULL)
{
delete ch;
}

}

7. Mistakenly Overwriting the pointer.This can happen in following possible ways.
a.
char *ch = new char(100);
char *ch1 = new char(100);
ch1 = ch;// We lost memory allocated by ch1

b.
vector<char*> list;
list.push_back(new char(10));
list[0] = new char(100);//Overwriting the first pointer

c.
map<int, char*> myMap;
myMap[1] = new char(10);
myMap[1] = new char(100);//Overwriting the pointer with key 1

The solution will be to be careful while assigning a pointer to other. It is advised to make sure that the pointer on left side is NULL.
{
char *ch = new char(100);
char *ch1 = new char(200);
if(ch == NULL)
{
ch = ch1;
}

}

This is applicable to vectors/list/Maps or such STL containers also.

8. In c++ deleting a pointer of base class type when its pointing to a child class object, can cause memory leak if the base class destructor is not declared virtual.

class A
{
public:
A()
{ }

~A()
{
cout << "Destroy A" << endl;
}
};

class B : public A
{
private:
char *ch;
public:
B()
{
ch = new char(100);
}
~B()
{
delete ch;
cout << "Destroy B" << endl;
}
};
int main()
{
A* a = new B();
delete a;
}

The Solution is to declare the ~A() as virtual as follows
virtual ~A(){ }
This makes sure that the destructor of child class is called before the parent class destructor.

So, this is the list that I could come up with. Some of the examples are very trivial, but in a real time code the same scenario occurs in a different way, may be spanning some functions/classes of files. So, its quite difficult to find some of those.

But following of few prgramming practices can minimize the effort to debug the memory leaks.One of them is make sure pointer is NULL before allocating and explicitly assign that pointer to NULL after calling delete. The second one is because delete does not assign the pointer NULL after freeing the allocated memory.
if(pointer == NULL)
{
//Allocate memory using the pointer
}
delete pointer;
pointer = NULL;

Another thing is to keep in mind while deleting a pointer is to check if its not NULL of already freed.This should be done to get rid of any double-delete issues.
if(pointer != NULL)
{
delete pointer;
pointer = NULL;
}

Wishing all of you programmers a best of luck in making your code Mem Leak free. Please provide comments or suggestions if any. Or please add any scenario if I have missed. Hope you will be able to spend time on facebook or orkut as much as possible but make sure your manager is not aware that you are freeeeee.

cya !!!