MFC下使用opencv出现内存泄露的解决办法

一、现象描述

在MFC程序里只要在头文件或者cpp文件定义了Mat变量,不管该Mat是否为空,在程序退出时VisualStio都会提示发生内存泄露。下面以单文档程序为例进行说明。

class CMainFrame : public CFrameWndEx

{

     private:

Mat m_Img;

};

在CMainFrame里定义Mat m_Img。按F5调试,程序退出后在输出窗口提示如下:

线程 'Win32 线程' (0x78c) 已退出,返回值为 0 (0x0)。
Detected memory leaks!
Dumping objects ->
{141} normal block at 0x004A4E80, 29 bytes long.
 Data: <     NJ  NJ     > 00 00 00 00 90 4E 4A 00 97 4E 4A 00 00 00 00 00 
{140} normal block at 0x004A4E08, 57 bytes long.
 Data: <    (        MJ > 00 00 00 00 28 00 00 00 00 00 00 00 90 4D 4A 00 
{139} normal block at 0x004A4D90, 54 bytes long.
 Data: <    (    NJ  MJ > 00 00 00 00 28 00 00 00 08 4E 4A 00 18 4D 4A 00 
{138} normal block at 0x004A4D18, 53 bytes long.
 Data: <    (    MJ  LJ > 00 00 00 00 28 00 00 00 90 4D 4A 00 98 4C 4A 00 
{137} normal block at 0x004A4C98, 61 bytes long.
 Data: <    (    MJ  LJ > 00 00 00 00 28 00 00 00 18 4D 4A 00 20 4C 4A 00 
{136} normal block at 0x004A4C20, 53 bytes long.
 Data: <    (    LJ  KJ > 00 00 00 00 28 00 00 00 98 4C 4A 00 A0 4B 4A 00 
{135} normal block at 0x004A4BA0, 61 bytes long.
 Data: <    (    LJ (KJ > 00 00 00 00 28 00 00 00 20 4C 4A 00 28 4B 4A 00 
{134} normal block at 0x004A4B28, 56 bytes long.
 Data: <    (    KJ     > 00 00 00 00 28 00 00 00 A0 4B 4A 00 00 00 00 00 
Object dump complete.
程序“[9380] TestOpencv.exe: 本机”已退出,返回值为 0 (0x0)。


值得注意的定义其它opencv数据类型,均不会提示内存泄露,比如IplImage*,Rect,Point等。


二、原因探究

        Mat作为opencv里的基本图像数据类,本身自带析构函数,所以定义一个Mat变量理论上是不会导致内存泄露的。而且即便在MainFram的析构函数里显示调用Mat的析构函数,程序退出时依然提示内存泄露。但是用其它的内存泄露检测工具,比如Vld,却无法检测出该内存泄露。所以有理由怀疑是VisualStio误报。之前在网上看过一篇文章,说是因为opencv_core.dll比mfc dll先加载导致的。

“TestOpencv.exe”: 已加载“E:\OpencvTest\Debug\TestOpencv.exe”,已加载符号。
“TestOpencv.exe”: 已加载“C:\Windows\System32\ntdll.dll”,已加载符号
“TestOpencv.exe”: 已加载“C:\Windows\System32\kernel32.dll”,已加载符号
“TestOpencv.exe”: 已加载“C:\Windows\System32\KernelBase.dll”,已加载符号
“TestOpencv.exe”: 已加载“D:\Program Files\opencv\build\x86\vc10\bin\opencv_core245d.dll”,已加载符号
“TestOpencv.exe”: 已加载“C:\Windows\System32\msvcp100d.dll”,已加载符号。
“TestOpencv.exe”: 已加载“C:\Windows\System32\msvcr100d.dll”,已加载符号。
“TestOpencv.exe”: 已加载“C:\Windows\System32\mfc100ud.dll”,已加载符号。

程序退出后在输出窗口可以看到,opencv_core245d.dll在mfc的dll之前加载。

三、解决之道

  1.(不推荐做法)将”配置属性>常规>MFC的使用“ 由“在共享 DLL 中使用 MFC”修改为“在静态库中使用 MFC”。

       这种方式是很多人采取的做法,但是我不推荐这么做,因为静态库的效率较低,而且当工程比较庞大时,调用其它使用opencv的dll时,会导致莫名其妙的崩溃。

  2.(推荐做法)采取dll延迟加载技术。


  因为mfc下内存泄露主要是由于Mat这个数据类型造成的,因此只需要延迟加载定义Mat的opencv_cored.dll即可。

3.(推荐做法)将Mat封装到dll之中,在mfc应用程序中不要出现Mat。

方法二可以解决一些比较简单mfc工程下使用opencv导致的内存泄露问题,但是如果一个大型MFC应用工程,调用了很多不同类型的dll,既有win32的dll,又有mfc的dll,而且这些dll都需要用到opencv,这时候通过方法2中的设置,可能会出现opencv_cored.dll还是在mfc dll之前加载。

在工程实践中,我发现如果将需要用到opencv实现的功能封装成dll,不管是win32的还是mfc的都行,再通过mfc应用程序进行调用,是不会提示内存泄露的。



评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值