一种MFC内存泄露误报的情况

一.环境

操作系统:Windows2003 server

IDEvs2003

二.现象

新建一个dll的空项目,加入mydll.hmydll.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.dllmydll.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 7832字节的内存泄漏,内容为:Dll:this is my d...,从内容可以看出,这是mydll中全局string变量description的值。

MFCDEBUG版本中使用_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被调用,该函数的参数dwReasonDLL_PROCESS_DETACH,表示这是在卸载mfc71d.dll,继续运行,程序停在std::string::~string断点处,跟踪可知这是字符串变量description。由此可说明:由于mfc71d.dllmy.dll的全局变量释放之前被卸载导致输出内存泄漏报告,但实际上并没有内存泄漏。可将VoidFunc函数中的teststr变量改为static,也可看到报告该变量内存泄漏。

四.结论

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

五.也许没有结束

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

 

 
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页