MFC内存泄露误报的情况

一.环境

操作系统:Windows2003 server

IDE:vs2003

 

 

二.现象

新建一个dll的空项目,加入mydll.h和mydll.cpp两个文件,内容如下:

// mydll.h

#ifndef _MYDLL_H_

#define _MYDLL_H_

__declspec( dllexport ) void VoidFunc();

#endif

 

 

// mydll.cpp

#include "mydll.h"

#include <string>

const std::string description = "Dll:this is my dll";

void VoidFunc()

{

    const std::string teststr = "Func:VoidFunc string";

}

采用“多线程调试 DLL”编译,生成mydll.dll和mydll.lib。

新建一个MFC工程,使用“在共享 DLL 中使用 MFC”,导入mydll.lib,可在某处(例如OnButtonClick等)调用VoidFunc。使用DEBUG版本编译运行,在窗口退出时在IDE的输出窗口可看到:

Detected memory leaks!

Dumping objects ->

{112} normal block at 0x 00365C 78, 32 bytes long.

Data: <Dll:this is my d> 44 6C 6C 3A 74 68 69 73 20 69 73 20 6D 79 20 64

Object dump complete.

很明显,输出表明有内存泄漏。

 

三.分析

根据IDE输出内容看,在内存地址为0x 00365C 78有32字节的内存泄漏,内容为:Dll:this is my d...,从内容可以看出,这是mydll中全局string变量description的值。

MFC在DEBUG版本中使用_malloc_dbg和_free_dbg进行分配和释放内存,__malloc_dbg将调用_heap_alloc_dbg进行内存分配,它将一些附加信息(大部分就是dump出来的信息)放在分配内存的前面(其实后面也有),所有分配的内存组成一个双向链表。相应的,_free_dbg将释放内存同时在链表中删除该节点。程序退出之前MFC检查这个链表就可查出内存泄漏情况。这里的细节可查看CRT源码的dbgheap.c文件。

同样,vc71携带的std::string实现的DEBUG版本也是使用_malloc_dbg和_free_dbg进行分配和释放内存,因此MFC是可以跟踪到mydll的内存分配的。难道dll的全局变量description确实没有释放内存吗?

在std::string::~string处设置断点调试,发现description有释放内存,MFC却报内存泄漏,这是怎么回事?

想起MFC是使用CRT函数_CrtDumpMemoryLeaks(dbgheap.c)来报告内存泄漏的,在该处设置断点,在调用堆栈回溯函数调用,发现是函数_DllMainCRTStartup被调用,该函数的参数dwReason为DLL_PROCESS_DETACH,表示这是在卸载mfc71d.dll,继续运行,程序停在std::string::~string断点处,跟踪可知这是字符串变量description。由此可说明:由于mfc71d.dll在my.dll的全局变量释放之前被卸载导致输出内存泄漏报告,但实际上并没有内存泄漏。可将VoidFunc函数中的teststr变量改为static,也可看到报告该变量内存泄漏。

 

 

四.结论

由于mfc71d.dll在其他动态库卸载之前被卸载导致输出内存泄漏报告,但实际上并没有内存泄漏。

 

 

五.也许没有结束

mfc71d.dll为什么在my.dll的全局变量释放之前(也就是在my.dll卸载之前)被卸载?隐式链接的动态库的卸载顺序的依据是什么,根据代码调用方式还是动态库依赖关系,还是其他什么?

 

注:在2005及WinXP中,该问题没有重现

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值