vs2019 - detected memory leak

news/2024/10/19 2:17:49/

文章目录

    • vs2019 - detected memory leak
    • 概述
    • 笔记
    • vs2019 console
    • vs2019 MFC Dlg
    • 但是,工程大了之后,VS2019提示的就变了样
    • 整好的内存泄漏侦测头文件和实现
    • my_debug_new_define.h
    • my_debug_new_define.cpp
    • 在所有.cpp文件入口处包含my_debug_new_define.h
    • 包含的细节 - 如果有预编译头文件(e.g. pch.h), 必须包含在pch.h后面
    • 包含的细节 - 如果工程中的.cpp头部已经重定向了new, 要在重定向之后包含my_debug_new_define.h
    • 如果看到了内存泄漏,却无法定位到具体代码行
    • 在工程中加入调试开始和结束函数
    • END

vs2019__detected_memory_leak_1">vs2019 - detected memory leak

概述

用VS2019建立的控制台工程, 在调试模式下, 如果出了内存泄漏,是没有提示的。
// 网上的大佬在2010年就给出了解决方法
// \ref https://www.codeproject.com/articles/66324/detecting-memory-leaks-using-the-crtdbg-library

笔记

分别在新建的VS2019 console和MFC Dlg程序中试试, 出现内存泄漏时,让VS2019IDE将内存泄漏点报出来,且能转到具体代码行。

vs2019_console_8">vs2019 console

// exp003_vs2019_console_detect_memory_leak.cpp
#include <iostream>
#include <crtdbg.h>
#define  new new(_CLIENT_BLOCK,__FILE__, __LINE__)// 新建vs2019控制台工程, 如果有内存泄漏, 默认是不提示的。
// 网上的大佬在2010年就给出了解决方法
// \ref https://www.codeproject.com/articles/66324/detecting-memory-leaks-using-the-crtdbg-libraryint main()
{_CrtMemState s1, s2, s3;_CrtMemCheckpoint(&s1);// Memory snapshot will be taken at this pointstd::cout << "Hello World!\n";uint8_t* pBuf = new uint8_t[100];_CrtMemCheckpoint(&s2);// Another Memory snapshot will be taken at this point// Memory difference which has been allocated but deallocted between s1 and s2 // Memory check points will be calculated. if (_CrtMemDifference(&s3, &s2, &s1)) {_CrtDumpMemoryLeaks();  //Dumps the memory leak in Debugger Window, if any, between s1 and s2 memeory check points.}return 0;
}

在这里插入图片描述

vs2019_MFC_Dlg_44">vs2019 MFC Dlg

新建后的工程,如果发生内存泄漏,也是有提示的。且能定位到具体代码行。
在这里插入图片描述

但是,工程大了之后,VS2019提示的就变了样

在这里插入图片描述
如果不是新建的工程,而是已经写了一段时间的工程,代码行数上来之后,在debug版的调试模式下,程序结束后,确实能看到IDE提示有内存泄漏。但是,无法直接定位到泄漏点。 这点,在以前工作中遇到的工程中,也遇到过。如果工程大了,出现了内存泄漏,就不那么好找。

工程大了,VS2019IDE大概率都定位不到具体哪些行引起的内存泄漏。

我在查资料之前,自己用笨办法搞定了。用排除法。让执行一个特定操作可以引起内存泄漏,那么就在这个模块中再用排除法去查。
不过,这得是自己写的工程。如果是同事维护的工程或者开源工程,用排除法基本没得搞。

这时该如何排查呢(是否可以让VS2019自动定位到内存泄漏点?)?我就是因为这个场景,才去查如何定位内存泄漏,才找到了网上大佬2010年就提出的解决方法。

但是,网上大佬的方法只适合工程没有hook new的场景。
e.g. MFC向导生成的工程,已经在debug模式下, 将new换成了DEBUG_NEW

// Memory tracking allocation
void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
#define DEBUG_NEW new(THIS_FILE, __LINE__)

这时,如果再使用crtdbg.h中的new重定向方法,直接编译不过,和MFC的重定向new是冲突的。只能是使用MFC重定向的new
这时再使用_CrtDumpMemoryLeaks,效果和不加是一样的(只能看到有内存泄漏,无法知道内存泄漏精确代码行)

观察了一下发现,在MFC工程中生成的.cpp顶部,都自己重新重定向了new


// MoneyCostParser.cpp: 定义应用程序的类行为。
//#include "pch.h"
#include "framework.h"
#include "MoneyCostParser.h"
#include "MoneyCostParserDlg.h"#ifdef _DEBUG
#define new DEBUG_NEW // !!!
#endif

// MoneyCostParserDlg.cpp: 实现文件#include "pch.h"
#include "framework.h"
#include "MoneyCostParser.h"
#include "MoneyCostParserDlg.h"
#include "afxdialogex.h"#ifdef _DEBUG
#define new DEBUG_NEW // !!!
#endif

再查看以前用MFC向导生成的类中的.cpp

// MyWorkerThread.cpp: implementation of the CMyWrokerThread class.
//
//#include "pch.h"
#include <process.h>
#include "CMyWrokerThread.h"#ifdef _DEBUG#undef THIS_FILE // !!!static char THIS_FILE[] = __FILE__; // !!!#define new DEBUG_NEW // !!!
#endif

再看自己工程,只能看到有内存泄漏,但是不知道具体泄漏行的场景。
最后用手工排除法确定了.cpp, 这个cpp是自己手写的。
最后试了一下,只要在非MFC生成的.cpp(包括自己手写的.cpp,或者是第三方的.cpp)顶部,加上重定向new的代码,就可以实现自动定位内存泄漏行。

如果在VS2019下,看到有内存泄漏的提示,但是无法定位到精确代码行,这时就要检查一下,是否每个.cpp的开头都有new的重定向代码。

如果是想让自己写的.cpp适用于控制台和MFC或者其他平台,就需要include一个头文件(这个头文件不包含条件包含的保护)进来。
然后按照各种平台的编译环境,将new换成debug new.

整好的内存泄漏侦测头文件和实现

my_debug_new_define.h

//! \file my_debug_new_define.h// 这个头文件是new的debug版定义, 要包含到每个需要的.cpp中,不能有头文件多重包含的保护
// my_debug_new_define.h 只能包含到.cpp中,不能包含到其他.h中#define PROG_TYPE_CONSOLE 1
#define PROG_TYPE_MFC 2#if defined(_MFC_VER)
#define MY_NEW_TYPE PROG_TYPE_MFC
#elif defined(_CONSOLE)
#define MY_NEW_TYPE PROG_TYPE_CONSOLE
#else
#error !!! unknown env, please fixed the code for detected memory leak
#endif// \ref https://learn.microsoft.com/zh-cn/cpp/preprocessor/hash-if-hash-elif-hash-else-and-hash-endif-directives-c-cpp?view=msvc-170
#if (defined MY_NEW_TYPE) && (PROG_TYPE_CONSOLE == MY_NEW_TYPE)#include <crtdbg.h>#ifdef new#undef new#endif#define  new new(_CLIENT_BLOCK,__FILE__, __LINE__)
#elif (defined MY_NEW_TYPE) && (PROG_TYPE_MFC == MY_NEW_TYPE)#ifdef _DEBUG#ifdef new#undef new#endif#define new DEBUG_NEW#endif
#endifvoid new_debug_begin();
void new_debug_end();

my_debug_new_define.cpp

//! \file my_debug_new_define.cpp#include "pch.h"
#include "my_debug_new_define.h"#if (defined MY_NEW_TYPE) && (PROG_TYPE_CONSOLE == MY_NEW_TYPE)
static _CrtMemState s1;
static _CrtMemState s2;
static _CrtMemState s3;
void new_debug_begin()
{_CrtMemCheckpoint(&s1);// Memory snapshot will be taken at this point
}void new_debug_end()
{_CrtMemCheckpoint(&s2);// Another Memory snapshot will be taken at this point// Memory difference which has been allocated but deallocted between s1 and s2 // Memory check points will be calculated. if (_CrtMemDifference(&s3, &s2, &s1)){_CrtDumpMemoryLeaks();  //Dumps the memory leak in Debugger Window, if any, between s1 and s2 memeory check points.}
}
#else
void new_debug_begin()
{
}void new_debug_end()
{
}
#endif

在所有.cpp文件入口处包含my_debug_new_define.h

包含的细节 - 如果有预编译头文件(e.g. pch.h), 必须包含在pch.h后面

//! \file CTest.cpp
//! \note 用VS2019类向导添加的非UI类,是没有DEBUG_NEW定义的#include "pch.h" // 如果工程中有预编译头文件(e.g. pch.h), 那么.cpp中要首先包含pch.h#include "my_debug_new_define.h" // <== 如果要包含头文件,都要在pch.h的后面
#include "CTest.h"int CTest::fn_add(int a, int b)
{char* p = new char[0x100]; // 模拟内存泄漏return (a + b);
}

包含的细节 - 如果工程中的.cpp头部已经重定向了new, 要在重定向之后包含my_debug_new_define.h


// exp005MfcDlg.cpp: 定义应用程序的类行为。
//#include "pch.h"
#include "framework.h"
#include "exp005MfcDlg.h"
#include "exp005MfcDlgDlg.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif#include "my_debug_new_define.h" // 如果向导生成的代码中已经重定向了new, 需要放到该代码后面,以便重定向new到crtdbg// Cexp005MfcDlgAppBEGIN_MESSAGE_MAP(Cexp005MfcDlgApp, CWinApp)ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()

如果看到了内存泄漏,却无法定位到具体代码行

检查一下,是否工程中所有的.cpp头部都包含了my_debug_new_define.h

在工程中加入调试开始和结束函数

// exp005Vs2019Console.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include "CTest.h"
#include "my_debug_new_define.h"int main()
{new_debug_begin(); // debug new beginchar* p = new char[66];CTest obj;obj.fn_add(1, 2);std::cout << "Hello World!\n";new_debug_end(); // debug new end
}

END


http://www.ppmy.cn/news/1425541.html

相关文章

Axios的七大特性

Axios是一个基于Promise的HTTP客户端&#xff0c;用于浏览器和Node.js环境中发起HTTP请求。它有许多强大的特性&#xff0c;下面将介绍Axios的七大特性。 1. 支持浏览器和Node.js Axios既可以在浏览器中使用&#xff0c;也可以在Node.js环境中使用&#xff0c;提供了统一的API…

计算机毕业设计springboot小区物业报修管理系统m8x57

该物业报修管理系统实施的目的在于帮助物业管理企业升级员工管理、住户管理、报修问题管理等内部管理平台&#xff0c;整合物业管理企业物力和人力&#xff0c;全面服务于维修人员管理的内部管理需求,并重视需求驱动、管理创新、与业主交流等外部需求,通过物业管理企业各项资源…

C++:STL-list模拟实现:迭代器的封装

STL-list模拟实现细节 一. 模拟实现的思想细节1.迭代器实现&#xff1a;用类进行封装2.和--的重载3.奇怪的->重载4.const迭代器 二.实现源码 一. 模拟实现的思想细节 1.迭代器实现&#xff1a;用类进行封装 为什么不使用原生指针&#xff1a; ​ 相比于vector和string&am…

对接浦发银行支付(三)-- QR扫码付

一、使用场景 扫码付&#xff0c;指的是支付平台&#xff0c;给每个用户的具体订单生成一个QR二维码&#xff0c;用户本人或者他人扫码付款。 付款用户可以直接识别二维码&#xff0c;或者下载到本地&#xff0c;通过微信或支付宝扫一扫识别&#xff0c;第二步将跳转至对应的支…

酷得智能 无人机方案开发

东莞市酷得智能科技有限公司&#xff0c;是一家专业的技术服务公司&#xff0c;致力于为各类智能硬件提供高效、稳定、安全的底层驱动解决方案。拥有一支经验丰富、技术精湛的团队&#xff0c;能够为客户提供全方位的底层驱动开发服务。 无人机功能介绍&#xff1a; 1、自动跟…

鸿蒙OpenHarmony【搭建Ubuntu环境】

搭建Ubuntu环境 在嵌入式开发中&#xff0c;很多开发者习惯于使用Windows进行代码的编辑&#xff0c;比如使用Windows的Visual Studio Code进行OpenHarmony代码的开发。但当前阶段&#xff0c;大部分的开发板源码还不支持在Windows环境下进行编译&#xff0c;如Hi3861、Hi3516…

Vue3:响应式数据的基本使用(ref、reactive)

一、前言 在Vue3中&#xff0c;如果数据不是响应式数据&#xff0c;当数据的值发生改变时&#xff0c;页面上的数据是不会发生改变的。因此本文主要介绍Vue3中响应式数据的使用&#xff0c;包括ref和reactive的基本使用。 二、ref 1、ref —— 创建基本类型的响应式数据 re…

创新指南|利用 AI 工具转变您的内容策略

内容策略涉及规划、创建和管理内容。无论您是在策划博客文章、社交媒体更新还是网站内容&#xff0c;精心制定的内容策略是营销活动成功的关键。然而&#xff0c;如果没有合适的工具&#xff0c;维持强大的内容策略可能会具有挑战性。这就是人工智能(AI) 工具发挥作用的地方&am…