2009-04-11 25 views
2

我在一些应用程序中有很多引用计数类,而且在那些应用程序使用的dll中,它们都继承并实现了一个IRefCounted接口。C++:调试引用计数系统中的内存泄漏

为了帮助找到这些内存泄漏的来源,我希望每个应用程序都维护存在的所有这些参考计数类的列表。

问题是管理这些列表的实例,使它们的用途不影响我的类的使用(例如,我不需要将指针传递给列表的所有时间,而是以某种方式将它附加到该过程)。

-Theres很好的机会,这些应用程序中的几个可能一次运行,并使用相同的DLL。每个应用程序都需要自己的对象列表,并且该应用程序加载的所有dll等都需要使用该列表(但要注意一个dll可能会被多个应用程序加载...)。
- 该列表必须在应用程序中的每个其他全局变量和静态变量之后销毁,因此列表中的对象在被破坏时留在列表中的对象未被正确释放。

然后,我会简单地添加一个断点到列表的析构函数,这样我就可以查看调试器中的任何未分配的对象。

+0

对不起,你的问题是? – 2009-04-11 13:49:21

回答

1

我猜你正在使用COM。您可能需要找到某种方式让weak pointer以便实例化对象的注册表不会被破坏。

如果您可以修改所有类,则可以注入一个静态成员来跟踪所有实例,并让实例的析构函数将其自身从静态成员中移除。例如,你可以使用一个基类或实用类像下面这样:

class InstanceRegistry { 
protected: 
    InstanceRegistry() { 
     registry.insert(this); 
    } 
    ~InstanceRegistry() { 
     registry.remove(this); 
    } 
private: 
    static SomeContainerType<InstanceRegistry*> registry; 
}; 

额外的工作需要,如果你想为不同类型的类不同的注册表做,等

+0

我没有使用COM,我可以添加一些东西到对象的con/destructor中以添加从列表中删除它们。列表probs不应该有对象的引用。 – 2009-04-11 16:02:52

+0

COM使用IUnknown,而不是IRefCounted。 – 2009-04-11 16:07:33

1

如果进程正在使用相同的DLL,每个进程都会获得该DLL的静态(或“全局”)数据的私有副本。

所以你需要做的就是使列表成为一个DLL中的全局变量,并从每个应用程序链接到该DLL。这样,就不需要传递任何附加信息。

由于多DLL过程中对象的毁坏顺序的不可预测性,您陷入困境的想法充满了困难。

mainWinMain函数的末尾转储列表的内容会简单很多。

如果您没有以一致的方式使用智能指针类,那就这样做。此外,它可能值得寻找循环引用计数 - 对象A有对象B的计数,反之亦然。这是未发布对象的常见原因。

更新:

要强制所有的静态析运行和释放对象,这样,那么你可以检查列表中的条目之后,你需要构建应用程序以某种方式。

假设您有一个非常小的EXE来启动进程,并加载了许多其他可以完成所有工作的DLL。这些其他DLL以某种方式(可能通过COM或COM类系统)以LoadLibrary加载。 LoadLibrary API的工作方式是将DLL加载到进程中,或者在DLL已经加载的情况下递增DLL上的内部引用计数器。 FreeLibrary API递减计数器直到达到零,然后卸载DLL(此时将执行该DLL的静态析构函数)。

为此,我们现在添加我们的诊断DLL,其中包含所有未完成引用计数对象的列表。所有其他DLL使用import-lib链接到诊断DLL,EXE也使用LoadLibrary。

main即将退出的EXE经过DLL列表处理它以前加载,并在所有这些调用FreeLibrary则。通过保持加载诊断DLL,它确保它仍然在那里。至少这是理论。

但是按照什么顺序应该卸载其他DLL?如果A.DLL具有指向B.DLL中定义的对象的静态指针,那么您最好首先卸载A.因此,您需要了解各种DLL如何形成“分层”体系结构,其中较高层依赖于较低层,从而为您提供卸载它们的安全顺序。另外,一旦卸载了所有的DLL,诊断列表中任何引用DLL中对象的条目现在都将指向堆上的有效数据,但vtable将指向已定义的代码通过现在已经卸载的DLL,所以你将无法调用这些对象的虚函数。你应该能够检查他们的数据。