我想用启用的Visual Studio内存泄漏检测器(Memory Leak Detector)
创建项目它总是工作正常,我可以通过在我的应用程序上运行大量测试然后检查报告来轻松找到内存泄漏。
但是在将OpenCV 3.0静态链接到我的项目后,我得到了一些误报。
例如,最令人沮丧的错误来自StereoBMImpl::compute
方法并致电:ocl::useOpenCL()
经过调试后,我找到了"泄漏的来源":
TLSData<CoreTLSData>& getCoreTlsData()
{
static TLSData<CoreTLSData> *value = new TLSData<CoreTLSData>();
return *value;
}
在分析了这段代码后,我们知道静态对象只被分配一次,一切都应该没问题。但现在我有一堆误报内存泄漏报告,如:
{1370349} normal block at 0x0E74D560, 24 bytes long.
Data: < > FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00
{1370348} normal block at 0x0E74D4E0, 64 bytes long.
Data: <` t > 60 D5 74 0E CD CD CD CD CD CD CD CD CD CD CD CD
现在很难在我的应用程序中发现一些真正的内存泄漏,因为OpenCV存在一系列误报。我也不能运行自动内存泄漏测试,因为输出总是包含一些泄漏。
有没有办法删除这些&#34;伪&#34;错误(如果可能,不更改OpenCV源代码)?这很烦人。
我认为其他内存泄漏检测器也会报告一些类似的伪泄漏,因为new
运算符在没有delete
的情况下执行(操作系统会自动清理对象)。
答案 0 :(得分:1)
我以一种非常肮脏的方式解决了这个问题,但我找不到更好的方法。该解决方案需要修改一个OpenCV文件(system.cpp)。如果您找到了更好的解决方法,请发表评论。我想更多的人可能会有类似的问题。
首先,我尝试使用@JamesMcNellis解决方案(来自上面的评论)解决问题,明确将该块标记为_IGNORE_BLOCK:new (_IGNORE_BLOCK, __FILE__, __LINE__)
。这是解决这个问题的良好开端。不幸的是,泄漏类包含例如std::vector
,因此跟踪此向量的分配并未暂停。
我开始阅读来自crtdbg.h
的函数的MSDN文档,我找到了暂停内存泄漏检查一段时间的方法。通过清除标记&#39; _CRTDBG_ALLOC_MEM_DF&#39;使用函数:_CrtSetDbgFlag
。使用MSDN上的示例检查详细信息:_CrtSetDbgFlag documentation。
这个解决方案可能有一个缺点(我知道),它会暂停检查所有线程的内存泄漏。
最后使用RAII和一些宏定义,我创建了一个简单的类来管理这个功能。
我应用于官方3.0源代码的所有更改。
在OpenCV的system.cpp
文件的顶部(在precomp.hpp之后)的某处,我添加了简单的机制:
#if defined(_MSC_VER) && defined(_DEBUG)
#include <crtdbg.h>
class MEMORY_LEAKS_CHECKING_SUSPENDER
{
public:
MEMORY_LEAKS_CHECKING_SUSPENDER()
{
value = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
int new_flag = value & (~_CRTDBG_ALLOC_MEM_DF);
_CrtSetDbgFlag(new_flag);
}
~MEMORY_LEAKS_CHECKING_SUSPENDER()
{
_CrtSetDbgFlag(value);
}
private:
int value;
};
#define SUSPEND_MEMORY_LEAKS_CHECKING MEMORY_LEAKS_CHECKING_SUSPENDER suspend_memory_leaks_checking
#else
#define SUSPEND_MEMORY_LEAKS_CHECKING
#endif
每次我想暂停内存泄漏检查时我必须添加:PAUSE_MEMORY_LEAKS_CHECKING;
它仅在Visual Studio Debug编译中启用。离开作用域(MEMORY_LEAKS_CHECKING_SUSPENDER
类的析构函数)后,内存泄漏跟踪会自动启用。
目前暂停我的OpenCV内存泄漏,我在函数中添加了暂停分配:
getTLSContainerStorage()
void* TLSDataContainer::getData() const
TLSData<CoreTLSData>& getCoreTlsData()
inline TLSStorage* TLSStorage::get()
(TLSStorage中的最后一次暂停可能已在主OpenCV存储库上修复 - 我简要检查了存储库)
每次修改都非常简单(例如第一次泄漏):
修改前:
static TLSContainerStorage& getTLSContainerStorage()
{
static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage();
return *tlsContainerStorage;
}
修改后:
static TLSContainerStorage& getTLSContainerStorage()
{
SUSPEND_MEMORY_LEAKS_CHECKING;
static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage();
return *tlsContainerStorage;
}
如果您修改了所有这些语句并仍然观察到内存泄漏,并将OpenCV用作单独加载的dll,请确保使用FreeLibrary
函数正确卸载此dll。因此,在OpenCV DLLMain
文件和system.cpp
变量用法中检查cv::__termination
函数。
答案 1 :(得分:0)
我在项目中遇到了同样的问题:静态生成-MFC和OpenCV。这些解决方案对我没有帮助。我使用OpenCV版本3.4.3和4.0.1测试了它们。当所有opencv函数都放入自己的dll中时,问题就消失了。因此,我的项目配置如下:MFC构建-静态,OpenCV-动态
答案 2 :(得分:-1)
好的,我有另一种解决方法:
创建一个特殊函数,比如prefetchOpenCvMemoryLeaks()
,它创建/销毁一个小矩阵,创建/销毁一个小窗口,依此类推,以便OpenCV
泄漏饱和。
在外部main()
函数中,使用_CrtMemCheckpoint()
保存堆状态,调用整个项目,最后再次保存堆状态,并将其与旧_CrtMemDifference()
进行比较。< / p>
通过这种方式,您可以检查自己的内存泄漏,无论OpenCV
个是什么。