用VLD调查VC内存泄漏

一、发现内存泄漏

使用VS2022,发现提示有内存泄漏,检查了所有的new,确认都有相应的delete释放。

Detected memory leaks!
Dumping objects ->
{1914} normal block at 0x0000021FDFFBD2E0, 48 bytes long.
 Data: <`               > 60 E2 FB DF 1F 02 00 00 CD CD CD CD CD CD CD CD 
{1907} normal block at 0x0000021FDFFC22C0, 16 bytes long.
 Data: <8               > 38 F5 FA DF 1F 02 00 00 00 00 00 00 00 00 00 00 
{1838} normal block at 0x0000021FDFFBCE10, 48 bytes long.
 Data: <                > 90 DF FB DF 1F 02 00 00 CD CD CD CD CD CD CD CD 
{1831} normal block at 0x0000021FDFFCCE10, 16 bytes long.
 Data: <8               > 38 FB FA DF 1F 02 00 00 00 00 00 00 00 00 00 00 
{1699} normal block at 0x0000021FDFFBCB00, 48 bytes long.
 Data: <@               > 40 BB F8 DF 1F 02 00 00 88 BB F8 DF 1F 02 00 00 
{1692} normal block at 0x0000021FDFFCD450, 16 bytes long.
 Data: <8               > 38 F9 FA DF 1F 02 00 00 00 00 00 00 00 00 00 00 
{1683} normal block at 0x0000021FDFFBD0B0, 48 bytes long.
 Data: <        X       > 10 AF F8 DF 1F 02 00 00 58 AF F8 DF 1F 02 00 00 
{1676} normal block at 0x0000021FDFFCCDC0, 16 bytes long.
 Data: <                > B8 F4 FA DF 1F 02 00 00 00 00 00 00 00 00 00 00 
Object dump complete.

手工很难排查,需要使用工具了。

二、安装VLD

从往上搜索下载VLD,Visual Leak Detector | Enhanced Memory Leak Detection for Visual C++

下载最新版,双击安装,默认路径在C:\Program Files (x86)\Visual Leak Detector\下。

三、设置编译环境

在主程序的stdafx.h文件中,afxwin.h头文件之前,加入vld.h头文件。

// 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏
#define _AFX_ALL_WARNINGS

#include "vld.h"

#include <afxwin.h>         // MFC 核心组件和标准组件
#include <afxext.h>         // MFC 扩展


#include <afxdisp.h>        // MFC 自动化类

添加头文件路径:C:\Program Files (x86)\Visual Leak Detector\include;

添加vld.lib类库应用

把C:\Program Files (x86)\Visual Leak Detector\bin\Win64和C:\Program Files (x86)\Visual Leak Detector\lib\Win64目录下的所有文件都复制到当前工程的.\x64\Debug路径下。添加类库的路径:

然后编译即可。

四、检测内存泄漏

运行之后,查看程序加载的模块,确认vld类库加载成功

退出程序,显示VLD已经检测出内存泄漏,单给出的信息不明所以。。

WARNING: Visual Leak Detector detected memory leaks!
---------- Block 22 at 0x00000000962B2B80: 248 bytes ----------
  Leak Hash: 0x656456F1, Count: 1, Total 248 bytes
  Call Stack (TID 19720):
    ucrtbased.dll!malloc_dbg()
    mfc140d.dll!0x00007FFFC44332DA()
    mfc140d.dll!0x00007FFFC4579350()
    mfc140d.dll!0x00007FFFC457938D()
    mfc140d.dll!0x00007FFFC49A8C95()
    mfc140d.dll!0x00007FFFC4908D3A()
    mfc140d.dll!0x00007FFFC4908430()
    mfc140d.dll!0x00007FFFC4A2C92C()
    mfc140d.dll!0x00007FFFC4A26474()
    mfc140d.dll!0x00007FFFC4531F05()
    mfc140d.dll!0x00007FFFC451D9E0()
    mfc140d.dll!0x00007FFFC451C1B8()
    mfc140d.dll!0x00007FFFC444839B()
    mfc140d.dll!0x00007FFFC47A163E()
    E:\Work\09.SourceCode\ArtecRoth.cpp (71): ArtecRoth.exe!CArtecRothApp::InitInstance()
    mfc140d.dll!0x00007FFFC4A2CA3C()
    D:\a\_work\1\s\src\vctools\VC7Libs\Ship\ATLMFC\Src\MFC\appmodul.cpp (26): ArtecRoth.exe!WinMain()
    D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl (107): ArtecRoth.exe!invoke_main()
    D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl (288): ArtecRoth.exe!__scrt_common_main_seh() + 0x5 bytes
    D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl (331): ArtecRoth.exe!__scrt_common_main()
    D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_winmain.cpp (17): ArtecRoth.exe!WinMainCRTStartup()
    KERNEL32.DLL!BaseThreadInitThunk() + 0x14 bytes
    ntdll.dll!RtlUserThreadStart() + 0x21 bytes
  Data:
    00 00 00 00    00 00 00 00    08 80 30 96    28 01 00 00     ........ ..0.(...
    28 1A 10 6F    00 00 00 00    58 75 D0 C4    FF 7F 00 00     (..o.... Xu......
    28 0A 2E 96    28 01 00 00    FD 19 10 11    00 00 00 00     (...(... ........
    C8 75 D0 C4    FF 7F 00 00    88 2B 2B 96    28 01 00 00     .u...... .++.(...
    B3 14 10 C4    FF FF FF FF    98 75 D0 C4    FF 7F 00 00     ........ .u......
    10 0A 2E 96    28 01 00 00    20 1A 10 3E    00 00 00 00     ....(... ...>....
    A8 75 D0 C4    FF 7F 00 00    00 00 00 00    00 00 00 00     .u...... ........
    91 18 10 01    00 00 00 00    68 75 D0 C4    FF 7F 00 00     ........ hu......
    40 0A 2E 96    28 01 00 00    4B 1A 10 65    00 00 00 00     @...(... K..e....
    88 75 D0 C4    FF 7F 00 00    E8 2B 2B 96    28 01 00 00     .u...... .++.(...
    22 1A 10 3C    00 00 00 00    B8 75 D0 C4    FF 7F 00 00     "..<.... .u......
    E0 09 2E 96    28 01 00 00    50 1A 30 1B    00 00 00 00     ....(... P.0.....
    D8 75 D0 C4    FF 7F 00 00    70 0A 2E 96    28 01 00 00     .u...... p...(...
    12 17 30 FD    FF FF FF FF    E8 75 D0 C4    FF 7F 00 00     ..0..... .u......
    48 2C 2B 96    28 01 00 00    47 1A 30 53    00 00 00 00     H,+.(... G.0S....
    F8 75 D0 C4    FF 7F 00 00                                   .u...... ........

说明内存泄露没有发生在主程序中,把上面的编译设置从主程序中去除,在下面调用的dll工程中按同样的方法设置,多个dll工程的话,需要挨个试。

 在dll工程中设置,重新编译后,运行结果果然找到了具体位置。

---------- Block 3747 at 0x00000000C2B10AD0: 48 bytes ----------
  Leak Hash: 0x60ABD716, Count: 1, Total 48 bytes
  Call Stack (TID 20788):
    mfc140d.dll!0x00007FFFC4093200()
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\xmemory (78): AtcTransRoth.dll!std::_Default_allocate_traits::_Allocate()
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\xmemory (235): AtcTransRoth.dll!std::_Allocate<16,std::_Default_allocate_traits,0>() + 0xC bytes
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\xmemory (836): AtcTransRoth.dll!std::allocator<TransCoil *>::allocate()
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\vector (1673): AtcTransRoth.dll!std::vector<TransCoil *,std::allocator<TransCoil *> >::_Reallocate_exactly() + 0x10 bytes
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\vector (1750): AtcTransRoth.dll!std::vector<TransCoil *,std::allocator<TransCoil *> >::reserve()
    E:\Work\AtcArray.h (114): AtcTransRoth.dll!vector<TransCoil *>::Reserve() + 0x13 bytes
    E:\Work\AtcRothData.cpp (182): AtcTransRoth.dll!CAtcRothData::GetCoils()
    E:\Work\AtcRothData.cpp (831): AtcTransRoth.dll!CAtcRothData::CreateElement() + 0x1B bytes
    E:\Work\AtcRothData.cpp (616): AtcTransRoth.dll!CAtcRothData::LoadSchemaFromXml() + 0x13 bytes
    E:\Work\AtcRothData.cpp (34): AtcTransRoth.dll!CAtcRothData::LoadData() + 0x21 bytes
    E:\Work\ArtecRothDlg.cpp (207): ArtecRoth.exe!CArtecRothDlg::OnEnChangeMfceditbrowse1() + 0x41 bytes
    mfc140d.dll!0x00007FFFC44A21CC()
    mfc140d.dll!0x00007FFFC44A1A06()
    mfc140d.dll!0x00007FFFC4508F2C()

从提示的信息上看是vector申请的内存没有释放。通过仔细查看, 确认是TransWindingElementCoil 结构体中出现了内存泄漏,问题出在了结构体的继承上。

struct TransWindingElement
{
	CString chName;
	CString chLabel;
	AemTransElement emType;
	AemTransJoint emJoint;
};

struct TransWindingElementCoil : TransWindingElement
{
	vector<TransCoil*> arCoil;
};

在delete释放TransWindingElementCoil  对象是,由于保存的是父结构体的指针,只调用了TransWindingElement的析构函数,而没有调用TransWindingElementCoil 对象的析构函数,造成了vector对象所在内存空间的泄漏。

五、处理方法

给父结构体加虚析构函数

struct TransWindingElement
{
    virtual ~TransWindingElement() {}
	CString chName;
	CString chLabel;
	AemTransElement emType;
	AemTransJoint emJoint;
};

struct TransWindingElementCoil : TransWindingElement
{
	vector<TransCoil*> arCoil;
};

运行再无内存泄漏。

六、结束

在编程是需要时刻观察内存泄漏信息,出现内存泄漏要及时处理。堆积时间越长,则越难处理,尤其在运行计算的大循环中,调式内存泄漏极其麻烦。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值