0

我们有自己的智能指针类,它使用基本的 AddRef 和 Release 进行引用计数。

在调试时,我可以看到很多对象没有被正确释放。我可以看到哪些对象没有被释放,但很难找出它们是从哪个位置分配的。

有没有好的设计模式来解决这个问题?

我已经放置了调试语句和 ADDREF 和 RELEASE,当调用 release 时我可以看到引用计数。在某些情况下它大于 1,这意味着指针没有被删除。

如果我开始在 shared_ptr const 上放置断点,那么它将被调用数百次并且很难查明内存泄漏。

似乎创建了一些导致这些泄漏的循环引用。

4

2 回答 2

2

不要为此使用设计模式。不要仅仅为了检测泄漏而添加代码膨胀。

使用记忆工具。我想到了 Valgrind,还有一些用于 Windows 的商业产品。

还...

我可以看到哪些对象没有被释放,但很难找出它们是从哪个位置分配的。

为什么?在对象的构造函数中设置断点。或者使用标准指针 ( std::shared_ptr, std::unique_ptr)。

根据您的编辑:

我已经放置了调试语句和 ADDREF 和 RELEASE,当调用 release 时我可以看到引用计数。在某些情况下它大于 1,这意味着指针没有被删除。

您是否考虑了复制省略 (RVO/NRVO)?这似乎更有可能是原因。

于 2012-10-09T17:39:03.290 回答
1

几年前,之前auto_ptr,我编写了自己的智能指针类,我们在代码库中广泛使用了它。当然,里面塞满了虫子。

我有完全相同的问题。虽然我无法向您展示我用来识别资源泄漏源的调用站点的实际代码(因为代码不再存在),但我可以告诉您我做了什么。

第一件事是我写了一个#define宏 >SHUDDER<,类似于我在这里概述的那个,我可以用它来代替new分配我的对象。宏向智能指针发送附加参数,指示调用站点的文件和行号。智能指针会保留这个。

然后new,当我说出#defines打开此功能的神奇咒语时,我用我的宏替换了全局。显然,这应该在所有 Releasse 版本中禁用,并且仅在您实际调试this时在 Debug 版本中使用。

然后我让我的程序运行,直到我想查看所有呼叫站点。我会dump_call_sites()在那里的智能指针上执行一个方法,它将static vector调用站点字符串转储到标准输出。因此发现了问题,我会恢复所有那些神奇的咒语来关闭所有这些 hokus pokus。

这是真正的 hack-n-slash 编码。它远非优雅,它引入了它自己的一系列问题。但随着printf调试,它也有它的位置。如果您不想或无法加载您的 Rational Purify 或 Bounds Checker 类型的产品,这可以帮助您快速确定泄漏的来源。

于 2012-10-09T18:23:26.560 回答