Reputation: 55
I'm struggling to fix a memory leak coming from a third-party software package (Zinc Application Framework, a GUI windows framework, circa 1999 [!]). I'm working on a Windows 7 machine using Microsoft Visual Studio 2005 C++ (hold the gasps, please). I'm curious if anyone has any insight into what might be wrong.
Below is the message I get indicating that there is a memory leak:
Detected memory leaks!
Dumping objects ->
{291} normal block at 0x003DE228, 36 bytes long.
Data: <` > 60 B6 1D 10 00 00 00 00 00 00 00 00 00 00 CD CD
Object dump complete.
The program '[3496] TempZAF3.exe: Native' has exited with code 0 (0x0).
Tracing to the memory allocation block 291, I go into the following method:
long ZafCache::Get(long type, long value)
{
// Find a matching cache element.
CacheElement *element;
for (element = (CacheElement *)First(); element; element = (CacheElement *)element->Next())
if (element->type == type && element->value == value)
{
// Move the element to the front of the list because it is
// most recently used.
if (element != first)
{
ZafList::Subtract(element);
ZafList::Add(element, first);
}
element->useCount++;
return element->handle;
}
// Create a cache element if one didn't already exist.
long handle = CreateFunction(type, value);
element = new CacheElement(type, value, handle);
ZafList::Add(element, first);
// Remove a cache element if the cache is full.
if (++count >= size)
{
element = (CacheElement *)last;
if (element->useCount <= 0)
{
ZafList::Subtract(element);
DestroyFunction(element->type, element->value, element->handle);
delete element;
element = ZAF_NULLP(CacheElement);
count--;
}
}
return handle;
}
The debugger brings me specifically to the following line of code from the above method:
element = new CacheElement(type, value, handle);
Aha. There is no "delete element" command following this code, at least in this method. So apparently here is the culprit--we allocate memory for the CacheElement, and we never free the memory.
Great! So let's simply delete the element after adding it to the the static ZafList, and see if that gets rid of the problem. Nope--we get an unhandled exception, with an access violation reading some location. Ok, let's try a little experiment. We'll comment out the line of code
//ZafList::Add(element, first);
and add a
delete element;
Bingo. No more memory leak. Only problem is we actually want to add the element to the ZafList.
Here is the code for the ZafList::Add method:
ZafElement *ZafList::Add(ZafElement *newElement, ZafElement *positionElement)
{
// Add the element to the list.
if (!first) // Put at the first of the list.
{
newElement->previous = newElement->next = ZAF_NULLP(ZafElement);
first = last = newElement;
}
else if (!positionElement) // Put at the end of the list.
{
newElement->previous = last;
newElement->next = ZAF_NULLP(ZafElement);
last->next = newElement;
last = newElement;
}
else // Put before the specified element.
{
newElement->previous = positionElement->previous;
newElement->next = positionElement;
if (!positionElement->previous)
first = newElement;
else
positionElement->previous->next = newElement;
positionElement->previous = newElement;
}
++count;
return (newElement);
}
Here is the code showing the relationships between ZafList and ZafCache, and ZafElement and CacheElement:
// Cache used for cacheing GDI pens and brushes.
class ZafCache : public ZafList
{
public:
ZafCache(int size,
long (*CreateFunction)(long type, long value),
void (*DestroyFunction)(long type, long value, long handle));
virtual ~ZafCache(void);
long Get(long type, long value);
int Release(long handle);
private:
int count;
int size;
long (*CreateFunction)(long type, long value);
void (*DestroyFunction)(long type, long value, long handle);
class CacheElement : public ZafElement
{
public:
long handle;
long type;
long value;
int useCount;
CacheElement(long type, long value, long handle);
};
};
Should the ZafList destructor free the memory allocated for the CacheElement? Nominally, it looks like the ZafList destructor should do the job, as it calls the below method.
void ZafList::Destroy(void)
{
ZafElement *tElement;
// Delete all the elements in the list.
for (ZafElement *element = first; element; )
{
tElement = element;
element = element->next;
delete tElement;
tElement = ZAF_NULLP(ZafElement);
}
first = last = current = ZAF_NULLP(ZafElement);
count = 0;
}
And yet we're getting memory leaks. So the question boils down to: How can I free the memory that's allocated for the CacheElement after adding it to the ZafList? Thanks in advance for any suggestions!
Upvotes: 3
Views: 474
Reputation: 264411
The code all looks good.
But just because the memory leak software says there is a leak does not necessarily mean there is one. It could be that the memory leak detection code is being hooked in before the destructor of the list is being called (this can happen if the list is a file scope static storage duration object).
Upvotes: 2