You are here:

C++/Memory leak

Advertisement


Question
What is memory leakage in  OOPS concept and what is the best way to cutdown it???

Thanks

Answer
I do not think memory leaks are restricted to OOP. They are not confined to OOP, any style of programming can have memory leaks. A lot of OOP is concerned with concepts rather than low level details. It is at the low level details of specific languages and their memory management model and how they are used (or abused) that memory leaks occur.

A memory leak is a situation where a program obtains memory and fails to return it when finished with it, i.e. a program allocates memory and fails to release it.

Small one off memory leaks are not that important. Large memory leaks will obviously be more worrisome. Repeated memory leaks are the worst, especially in long running applications such as servers, where even a small memory leak repeated frequently will over time cause more and more memory to be allocated by the program. Eventually the process and quite probably the system as a whole will run out of memory, at which point it is likely to require re-starting (or re-booting the whole system if it effects it badly enough). Before that happens it is quite possible on modern desktop and server systems that the system will have so little free real memory that it will have to continually page memory to and from disk, causing the system to run slower and slower, forcing a re-boot even before a crash!

Some languages and development environments such as Java or .NET try to prevent memory leaks by using a memory management model called garbage collection. The system has a component that runs in conjunction with any applications. For Java this is part of the Java Virtual Machine (JVM). For .NET it will be part of an implementation of the Common Language Infrastructure (CLI) such as Microsoft's commercial implementation which is called the Common Language Runtime (CLR).

The garbage collector periodically looks for objects in memory that are no longer used and returns their memory to that available for use. An object is no longer used when nothing refers to it any longer. Modern garbage collectors can recognise situations where the only thing that refers to object A is object B and vise versa and longer such chains self-referring but otherwise unused sets of objects.

In such systems there is no need to specifically delete objects. However you can still get the effect of a memory leak by continually creating new objects and never letting go of all their references.

In C++ dynamically allocated memory (i.e. that allocated at runtime) has to be explicitly released. In C++ the operators for doing this are new (and new [] for arrays) and delete (and delete []). They create new objects, ensuring they are constructed properly (i.e. by calling a constructor for the object type), or delete objects no longer needed ensuring they are destroyed properly (i.e. by calling the destructor for the object type). From C, C++ has the library functions malloc to allocate raw memory and free to release a block of raw memory. They have to be used in pairs so:

An object created using new must be destroyed (and its memory returned for use) by using delete.

An array of objects created using new [] must be destroyed by using delete [].

Raw memory obtained calling malloc must be returned for use by calling free.

It is a bad idea to mix and match these pairings.

It is easy in such a setup to create new objects and forget to delete them thus creating a memory leak:

void Leaky(size_t size)
{
// dynamically create and array of ints
   int * values =  new[size];

// do something with them...

// Oops! Not deleted the array: memory for size ints is leaked
}

The above code creats an array of int dynamically. The number of elements in this array is specified by the size parameter passed to the function. There would typically be code that uses these values, and finally when done the array should be deleted using delete [] as, but I 'forgot' to do so to demonstrate leaking memory. This is the sort of memory leak that a garbage collector would correct: when values goes out of scope nothing else references the memory it pointed to, a garbage collector would spot this and re-claim the memory (hopefully calling the destructor first although such behaviour is not guaranteed in Java and .NET).

You might think that with care you can prevent such leaks. Consider the following:

void NotLeaky(size_t size)
{
   int * values =  new[size];

// do something with them...

// delete the values array, calling the destructor for each
// element (which for ints does nothing!) and returning the memory

   delete [] values;
}

This is all good until someone else comes along and makes changes and in doing so adds a return statement:

void NotLeaky(size_t size)
{
   int * values =  new[size];

// do something with them...

// Add some more stuff with a quick exit...

   if ( done )
   {
       return; // Whoops! We got a memory leak again.
   }

// Add rest of new stuff...

   delete [] values;
}

The new code might involve a loop or some conditions and the updating developer works out that a return is the quickest way to terminate at some point. That second route to returning now misses the delete [] and we have a memory leak if this new route is taken through NotLeaky.

The other way to exit a function in C++ is via an exception. If any of the code between values creation and deletion causes an exception to be thrown then again the array pointed at by values is not deleted and memory is lost.

Both these problems have fixes. In the first case we just ensure all resources are released before any return statement, which in this case means adding another delete [] before the return:

// ...

// Add some more stuff with a quick exit...

   if ( done )
   {
       delete [] values;
       return;
   }

// ...

Or we re-arrange the code to have a single return.

In the case of exceptions being thrown we have to catch them all possibly doing nothing with them and force a return via the delete[].
However this prevents handling of the exception higher up the call stack so a better solution is to catch any exception, delete the values array and re-throw the exception:

void NotLeaky(size_t size)
{
// dynamically create the number of ints specified by size
   int * values =  new[size];

   try
   {
   // do something with them...
   }
   catch ( ... )
   {
       delete [] values; // release resources
       throw;          // re-throw exception
   }

   delete [] values;
}

Obviously such code requires a lot of effort to remember to always get correct and is tedious to have to put in place. Unlike Java and .NET however C++ has deterministic rules for when destructors are called. One such rule is that however a function exits, be it via a return or function end or exception, all local stack objects created thus far in the function call will have their destructors called. This is very useful as it allows us to create classes to specifically manage resources in a smart fashion. Such types can be useful in any situation where a resource needs to be allocated and later released. For the handling of dynamic object resources these types are often called 'smart pointers'.

The (C++) idiom used is called Resource Acquisition Is Initialisation or RAII. I think this is a bit of a misnomer as what is really important is that the resource be released on destruction so maybe RRID (Resource Release Is Destruction) would be a better name. The idea is simple: on construction a resource is acquired and managed by such an object. When that object is destroyed (i.e. its destructor is called) it releases the resource. They also tend to have some way to access the resource managed.

In fact such types often have other ways to acquire and release the resource. A non-typical and rather heavyweight example is a std::fstream object. It can acquire an open file resource either during construction or later via a call to its open member function. Likewise the file is closed either by calling the close member function or when the std::fstream object is destroyed.

In the case of smart pointers we would construct them by passing them the pointer we wish managed. When the smart pointer is destroyed it makes sure the object pointed at by the managed pointer will (eventually) be deleted. I say eventually as smart pointers have various policies about when a managed object should be deleted. One obvious implementation would to just delete the managed object in its destructor. Another useful variant will allow the managed object to be shared and only delete the managed object when the last shared smart pointer managing the object is destroyed (sometimes likened to "last one out turns off the light"). Usually such shared pointer types cannot cope with cyclic self-referencing chains of objects. In this respect a garbage collector has the edge!

Smart pointers have access functions to allow the managed pointer to be used. Most will implement operator-> and operator*, allowing a smart pointer to be used much like an actual pointer. One caveat of the fact that there are two forms of new and delete (scalar and array) is that you need separate types of smart pointer to handle each. Smart pointer types for general use are usually implemented as template classes where the template type parameter is the type pointed to.

For examples of smart pointers see the Boost (http://www.boost.org/) smart pointer library at http://www.boost.org/libs/smart_ptr/smart_ptr.htm, and the C++ standard library std::auto_ptr (but note its odd usage).

I would say more but I am near my 10000 character answer limit, sorry. As to the best way to manage memory leaks. In C++, use smart pointers, but be aware of their various characteristics and idiosyncrasies, i.e. use the right tool for the job.

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.