用VLD调查VC内存泄漏

2023-10-06 23:20
文章标签 内存 泄漏 调查 vld vc

本文主要是介绍用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 bytesCall 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 bytesD:\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 bytesntdll.dll!RtlUserThreadStart() + 0x21 bytesData: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 bytesCall 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 bytesC:\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 bytesC:\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 bytesE:\Work\AtcRothData.cpp (182): AtcTransRoth.dll!CAtcRothData::GetCoils()E:\Work\AtcRothData.cpp (831): AtcTransRoth.dll!CAtcRothData::CreateElement() + 0x1B bytesE:\Work\AtcRothData.cpp (616): AtcTransRoth.dll!CAtcRothData::LoadSchemaFromXml() + 0x13 bytesE:\Work\AtcRothData.cpp (34): AtcTransRoth.dll!CAtcRothData::LoadData() + 0x21 bytesE:\Work\ArtecRothDlg.cpp (207): ArtecRoth.exe!CArtecRothDlg::OnEnChangeMfceditbrowse1() + 0x41 bytesmfc140d.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;
};

运行再无内存泄漏。

六、结束

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

这篇关于用VLD调查VC内存泄漏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/154521

相关文章

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Java内存区域与内存溢出异常的详细探讨

《Java内存区域与内存溢出异常的详细探讨》:本文主要介绍Java内存区域与内存溢出异常的相关资料,分析异常原因并提供解决策略,如参数调整、代码优化等,帮助开发者排查内存问题,需要的朋友可以参考下... 目录一、引言二、Java 运行时数据区域(一)程序计数器(二)Java 虚拟机栈(三)本地方法栈(四)J

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

Golang基于内存的键值存储缓存库go-cache

《Golang基于内存的键值存储缓存库go-cache》go-cache是一个内存中的key:valuestore/cache库,适用于单机应用程序,本文主要介绍了Golang基于内存的键值存储缓存库... 目录文档安装方法示例1示例2使用注意点优点缺点go-cache 和 Redis 缓存对比1)功能特性

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内