3

我正在努力修复来自第三方软件包(Zinc Application Framework,一个 GUI windows 框架,大约 1999 [!])的内存泄漏。我正在使用 Microsoft Visual Studio 2005 C++ 的 Windows 7 机器上工作(请屏住呼吸)。我很好奇是否有人对可能出现的问题有任何见解。

以下是我收到的消息,表明存在内存泄漏:

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).

追踪到内存分配块291,我进入如下方法:

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;
}

调试器将我带到上述方法的以下代码行:

element = new CacheElement(type, value, handle);

啊哈。至少在此方法中,此代码后面没有“删除元素”命令。显然,这是罪魁祸首——我们为 CacheElement 分配内存,而我们从未释放内存。

伟大的!因此,让我们在将元素添加到静态 ZafList 后简单地删除它,看看是否能解决问题。不——我们得到一个未处理的异常,读取某个位置的访问冲突。好的,让我们尝试一个小实验。我们将注释掉这行代码

//ZafList::Add(element, first);

并添加一个

delete element;

答对了。没有更多的内存泄漏。唯一的问题是我们实际上想要将元素添加到 ZafList。

下面是 ZafList::Add 方法的代码:

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);
}

下面是显示 ZafList 和 ZafCache 以及 ZafElement 和 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);
    };
};

ZafList 析构函数是否应该释放分配给 CacheElement 的内存?名义上,ZafList 析构函数似乎应该完成这项工作,因为它调用了以下方法。

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;
}

然而,我们遇到了内存泄漏。所以问题归结为:在将 CacheElement 添加到 ZafList 后,如何释放为 CacheElement 分配的内存?在此先感谢您的任何建议!

4

1 回答 1

2

代码看起来都不错。

但是仅仅因为内存泄漏软件说有泄漏并不一定意味着有一个。可能是内存泄漏检测代码在调用列表的析构函数之前被挂钩(如果列表是文件范围静态存储持续时间对象,则可能发生这种情况)。

于 2012-12-22T18:20:13.793 回答