Legal LeaksFiled Under: Weekly Tuesday Dose of goodness
This has been something that I’ve always wanted to talk about.
What’s lies beyond normal memory leaks, pointer ownership and memory corruption?
Legal Leaks!
This is also known as Design-Based Leaks. So why are they just as harmful as normal memory leaks?
Read on…
In C++, what is it that causes a memory leak? Take a look below:
Example 1:
{
cMyObject* obj = new cMyObject();
return;
} //leak after leaving scope
Example 2:
{
cMyObject* obj = new cMyObject();
if(obj.whatever() == 1)
{
delete(obj);
obj = NULL;
}
obj = new cMyObject(); //leak via re-assignment
}
So basically, it’s about calling new without delete right? Right, but we’ll not be talking about new and delete today.
In this article, let’s assume that memory management is handled, 0% chance of ANY form of memory leaks.
So are there any possibilities of memory leaks still? YES!
How so? Very simple. In games or any applications, we’ll definitely use dynamic data structures. What is that? Basically it refers to any data structures that can grow in size automatically.
One of the simplest of all is Linked List. Arrays are not considered since they have a fixed size.
Others can include Binary Trees (std :: map<K, T>) and so on.
So, how does a leak occur in such dynamic data structures? Let’s make one more assumption. That is, whatever that is stored inside is a native type. Not a pointer object, structure, stack object and so on. Therefore there is no issue of memory management here.
So a typical map of a float to int will look like this:
std :: map < float, int >
In StridesLib, it’ll be known as:
cMap< float, int >
Where K is a float, T is an int.
So how does the leak occur? Very simple. If I have a condition to insert elements into the map, I must have the equivalent condition to remove these elements from the map.
The crux is when such a condition is unbalanced and poorly designed, elements get orphanated in their respective data structures. Once that happens, you’re going to have a large number of redundant elements. That being said, it’s not an issue with natives, but it’s sure an issue with objects!
Therefore, after a period of time, with poor removal conditions in place, the data structure will continue to grow in size, achieving the same effect as normal memory leaks.
Eventually the application runs out of memory throwing a std :: bad_alloc (if I’m not mistaken), and the whole application collapses.
Such leaks are hard to detect and is almost invisible to memory leak detection tools such as Purify, KlocWork, Valgrind, and even Insure++ from Parasoft.
To be fair though, Insure++ has memory profiling user interface known as Inuse which helps identify memory usage and trends. From there, you can at least get a hint of which object type could be messing things up.
The root cause of such leaks however, is not due to poor coding standards or practices. Rather it’s due to poor technical and code design!
So how do we resolve such problems? Here’re the steps:
1) Detect the memory hogs
2) Have the design docs / technical specs beside you
3) Be prepared to draw a flow chart to depict the actual flow
4) Look out for suspicious logic flow
5) Question suspicious or inconclusive logic flow
6) Audit all data structures to see if they’re doing what they’re meant to do
Once you’ve confirmed that all these steps are adhered to, you’ll be technically overhauling the entire application. Tough right? Painful right? Serve you right for hastily implementing a poorly designed module!
If memory hogging aka legal leaks persists, then you can check on the following:
1) Is the memory used properly?
2) Are intended shallow copies passed in as pointers/references instead of by values?
3) Did you pass large data around by value? For example:
a) Data structures
b) Data buffers
c) Classes/Structures with large amount of attributes
You’ll have to reduce the amount temporary memory required to copy objects unnecessarily. This is to ensure that the OS is deallocating memory as fast as it’s allocating it.
That is, when you call new and delete, the respective memory held by you is allocated or deallocated in a timely fashion. Please note, the background CRT (C++ Runtime Library) is still but a supposedly well-coded library. But that doesn’t mean that it gives you 100% control on how fast or slow memory is being allocated and deallocated.
Suffice to say, if you make an application allocate memory faster than it deallocates, then you’ll suffer memory hogging as well.
Take note!
Have a nice weekend!
Jeremy
- Permalink
- Admin
- 17 Apr 2009 6:09 PM
- Comments (0)