Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:参考计数系统内存泄漏的调试_C++_Memory Leaks - Fatal编程技术网

C++ C++;:参考计数系统内存泄漏的调试

C++ C++;:参考计数系统内存泄漏的调试,c++,memory-leaks,C++,Memory Leaks,在我的一些应用程序中,以及这些应用程序使用的DLL中,我有许多引用计数类,它们都继承并实现了IRefCounted接口 为了帮助查找这些内存泄漏的来源,我希望每个应用程序都维护一个现有的所有这些引用计数类的列表 问题是如何管理这些列表的实例,使它们的使用不会影响我的类的使用(例如,我不需要一直传递指向列表的指针,而是以某种方式将其附加到进程) -这些应用程序中有几个很可能同时运行,并且使用相同的dll。每个应用程序都需要自己的对象列表,该应用程序加载的所有dll等都需要使用该列表(但请记住,一个

在我的一些应用程序中,以及这些应用程序使用的DLL中,我有许多引用计数类,它们都继承并实现了IRefCounted接口

为了帮助查找这些内存泄漏的来源,我希望每个应用程序都维护一个现有的所有这些引用计数类的列表

问题是如何管理这些列表的实例,使它们的使用不会影响我的类的使用(例如,我不需要一直传递指向列表的指针,而是以某种方式将其附加到进程)

-这些应用程序中有几个很可能同时运行,并且使用相同的dll。每个应用程序都需要自己的对象列表,该应用程序加载的所有dll等都需要使用该列表(但请记住,一个dll可能由多个应用程序加载…。
-列表必须在应用程序中每隔一个全局变量和静态变量之后销毁,因此,当列表被销毁时,列表中剩余的对象是truley未正确释放的对象

然后,我将简单地向列表的析构函数添加一个断点,以便在调试器中查看任何未分配的对象。

我猜您正在使用COM。您可能需要找到某种方法来创建一个实例,以便实例化对象的注册表不会阻止它们被破坏

如果可以修改所有类,那么可以插入一个静态成员来跟踪所有实例,并让实例的析构函数从静态成员中删除自身。例如,可以使用基类或实用程序类,如下所示:

class InstanceRegistry {
protected:
    InstanceRegistry() {
       registry.insert(this);
    }
    ~InstanceRegistry() {
       registry.remove(this);
    }
private:
  static SomeContainerType<InstanceRegistry*> registry;
};
class InstanceRegistry{
受保护的:
InstanceRegistry(){
登记处。插入(本);
}
~InstanceRegistry(){
删除(本);
}
私人:
静态SomeContainerType注册表;
};

如果需要为不同类型的类等使用不同的注册表,则需要进行额外的工作。

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

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

由于多DLL进程中对象销毁顺序的不可预测性,您捕获列表销毁的想法充满了困难

main
WinMain
函数末尾转储列表内容会简单得多

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

更新:

要强制所有静态析构函数运行并释放对象,以便以后可以检查列表中的条目,您需要以某种方式构造应用程序

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

在此基础上,我们现在添加了诊断DLL,其中包含所有未完成引用计数对象的列表。所有其他DLL都使用到诊断DLL的导入库链接,EXE也在其上使用LoadLibrary

main
即将退出时,EXE将遍历以前加载的DLL句柄列表,并对所有这些句柄调用FreeLibrary。通过保持诊断DLL加载,它可以确保它在最后仍然存在。至少这是理论

但是其他DLL应该以什么顺序卸载?如果A.DLL有指向B.DLL中定义的对象的静态指针,那么最好先卸载A.DLL。因此,您需要了解各种DLL是如何形成“分层”体系结构的,上层依赖于下层,从而为您提供一个安全的卸载顺序


此外,卸载所有DLL后,诊断列表中引用DLL中对象的任何条目现在都将指向堆上的有效数据,但vtable将指向已卸载的DLL定义的代码,因此您将无法对这些对象调用虚拟函数。不过,您应该能够检查它们的数据。

我没有使用COM,我可以向对象的con/destructor中添加一些内容,以将它们从列表中删除。列表问题不应引用objects.COM uses IUnknown,而不是IRefCounted。谢谢。COM注释已被删除。在winmain末尾转储列表的问题是,任何静态或全局智能指针仍将具有引用,这是完全安全的,因为它们将在对象被破坏时释放对象。因此,我真的需要在任何此类智能指针被销毁后查看此列表的状态。很好,除了99%的静态和全局变量在.exe模块中,该模块似乎在列表被销毁后仍被卸载。我想我可以将应用程序构建为DLL,并拥有一个包含列表的主机exe,加载应用程序,在该应用程序中调用WinMain,然后在WinMain返回时卸载和转储列表?没错,您需要重新组织应用程序,因为这是您能够指定卸载顺序的唯一方法。理想情况下,您应该完全避免使用静力学,但我怀疑您现在是否想听!)