vs2019 - detected memory leak

文章目录

    • 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

概述

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

笔记

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

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-library


int main()
{
    _CrtMemState s1, s2, s3;
    _CrtMemCheckpoint(&s1);// Memory snapshot will be taken at this point
    std::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

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

但是,工程大了之后,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
#endif

void 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

// Cexp005MfcDlgApp

BEGIN_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 begin

    char* 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.mfbz.cn/a/549428.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机系列之操作系统的系统

2、大话操作系统的启动 当按下开机键时&#xff0c;BIOS 就会开始执行 ​ BIOS 就是放在主板上 ROM 里面的一段程序。 ​ ROM Read Only Memory&#xff08;只能读取的内存&#xff09; ​ 所以 BIOS 在出厂的时候就可以直接写死在 ROM 里面。 ​ 每次开机的时候&#xff…

【数据结构与算法】之双向链表及其实现!

​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 数据结构与算法 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 目录 1、双向链表的结构及概念 2、双向链表的实现 2.1 要实现的接口…

Mac版2024 CleanMyMac X 4.15.2 核心功能详解 cleanmymac这个软件怎么样?cleanmymac到底好不好用?

近些年伴随着苹果生态的蓬勃发展&#xff0c;越来越多的用户开始尝试接触Mac电脑。然而很多人上手Mac后会发现&#xff0c;它的使用逻辑与Windows存在很多不同&#xff0c;而且随着使用时间的增加&#xff0c;一些奇奇怪怪的文件也会占据有限的磁盘空间&#xff0c;进而影响使用…

Android studio顶部‘app‘红叉- Moudle ‘XX.app’ dosen’t exist in project

Android studio顶部app红叉- Moudle ‘XX.app’ dosen’t exist in project 1、现象&#xff1a; 运行老项目或者有时候替换项目中的部分代码&#xff0c;明明没有错但是Android studio就编译报错了。 1.1 Android studio顶部app红叉。 1.2 点击Build没有clear菜单&#xff0…

软考 - 系统架构设计师 - 嵌入式真题

问题 1&#xff1a; &#xff08;1&#xff09;.HTML 静态化&#xff1a;可以实现对系统经常访问的页面进行静态化以提高系统访问的效率&#xff0c;但系统页面通常需要数据库中的用户信息和用户选择来动态显示&#xff0c;因此不适合采用。 HTML 静态化&#xff1a; 将动态生成…

windows下已经创建好了虚拟环境,但是切换不了的解决方法

用得多Ubuntu&#xff0c;今天用Windows重新更新anaconda出问题&#xff0c;重新安装之后&#xff0c;打开pycharm发现打开终端之后&#xff0c;刚开始是ps的状态&#xff0c;后面试了网上改cmd的方法&#xff0c;终端变成c盘开头了 切换到虚拟环境如下&#xff1a;目前的shell…

ON1 NoNoise AI 2024 for Mac/Win:智能降噪,重塑影像之美

在数字摄影领域&#xff0c;图片质量往往受到多种因素的影响&#xff0c;其中噪点问题尤为突出。ON1 NoNoise AI 2024作为一款专为Mac和Windows平台打造的AI图片降噪工具&#xff0c;凭借其卓越的降噪性能和智能化的操作体验&#xff0c;成为了摄影师和图像处理专家们的首选工具…

NL2SQL进阶系列(5):论文解读业界前沿方案(DIN-SQL、C3-SQL、DAIL-SQL、SQL-PaLM)、新一代数据集BIRD-SQL解读

NL2SQL进阶系列(5)&#xff1a;论文解读业界前沿方案&#xff08;DIN-SQL、C3-SQL、DAIL-SQL&#xff09;、新一代数据集BIRD-SQL解读 NL2SQL基础系列(1)&#xff1a;业界顶尖排行榜、权威测评数据集及LLM大模型&#xff08;Spider vs BIRD&#xff09;全面对比优劣分析[Text2…

基于Springboot+Vue的Java项目-免税商品优选购物商城系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

故障转移-redis

4.4.故障转移 集群初识状态是这样的&#xff1a; 其中7001、7002、7003都是master&#xff0c;我们计划让7002宕机。 4.4.1.自动故障转移 当集群中有一个master宕机会发生什么呢&#xff1f; 直接停止一个redis实例&#xff0c;例如7002&#xff1a; redis-cli -p 7002 sh…

Linux环境变量(一)

一.main参数 如果你仔细看过编程书籍就会发现&#xff0c;对于主函数main函数也是有参数的&#xff1a; 首先&#xff0c;我们先来认识两个参数&#xff1a; int main(int argc,char* argv[]) {return 0; } 对于这两个参数&#xff1a;第一个参数int类型表示为第二个的个数…

[C++][算法基础]判定二分图(染色法)

给定一个 n 个点 m 条边的无向图&#xff0c;图中可能存在重边和自环。 请你判断这个图是否是二分图。 输入格式 第一行包含两个整数 n 和 m。 接下来 m 行&#xff0c;每行包含两个整数 u 和 v&#xff0c;表示点 u 和点 v 之间存在一条边。 输出格式 如果给定图是二分图…

字体反爬知识积累2

一、os模块中函数的应用 如何获取当前文件中所有文件的路径方法 这段代码使用 os.walk()函数来遍历指定目录 imgs 下的所有子目录和文件。具体来说&#xff0c;os.walk()函数返回一个生成器&#xff0c;可以在每次迭代中获取目录树中的一个元组&#xff0c;元组包含当前目录的…

【算法】删除链表中重复元素

本题来源---《删除链表中重复元素》。 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入…

Delphi Xe 10.3 钉钉SDK开发——审批流接口(获取表单ProcessCode)

开发钉钉审批流时&#xff0c;需要用到钉钉表单的Processcode&#xff0c;有两种方法 &#xff1a; 一、手动获取&#xff1a; 管理员后台——审批——找到对应的表单&#xff1a;如图&#xff1a; ProcessCode后面就是了&#xff01; 二、接口获取&#xff1a;今天的重点&a…

Redis消息队列-基于Stream的消息队列-消费者组

7.5 Redis消息队列-基于Stream的消息队列-消费者组 消费者组&#xff08;Consumer Group&#xff09;&#xff1a;将多个消费者划分到一个组中&#xff0c;监听同一个队列。具备下列特点&#xff1a; 创建消费者组&#xff1a; key&#xff1a;队列名称 groupName&#xff1a…

SimpleImputer缺失数据处理报错解决方案

作者Toby&#xff0c;来源公众号&#xff1a;Python风控建模&#xff0c;SimpleImputer缺失数据处理报错解决方案 今天有学员反馈缺失值代码报错&#xff0c;由于sklearn缺失值处理的包升级&#xff0c;下面把官网最新的缺失值处理代码奉上。 参考https://scikit-learn.org/st…

LeetCode-热题100:101. 对称二叉树

题目描述 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a; root [1,2,2,3,4,4,3] 输出&#xff1a; true 示例 2&#xff1a; 输入&#xff1a; root [1,2,2,null,3,null,3] 输出&#xff1a; false 提示&#xff1a;…

数据库讲解---(数据更新、视图、数据控制)【MySQL版本】

目录 前言 一.数据更新 1.1插入数据 1.1.1插入单个元组 1.1.2将一个新学生记录(学号:091530,姓名:夏雨,性别:男,籍:海南,出生年份:1999,学院:计算机)插入到学生表中 1.1.3插入子查询结果 1.1.4有一个表“DEPT”(SDEPT CHAR(20),AVG_AGE SMALLINT)表示每个学院的学生的平…

蓝桥杯2024年第十五届省赛真题-R 格式(高精度乘法 + 加法)

本题链接&#xff1a;蓝桥杯2024年第十五届省赛真题-R 格式 - C语言网 题目&#xff1a;​​​​​​​ 样例&#xff1a; 输入 2 3.14 输出 13 思路&#xff1a; 根据题意&#xff0c;结合数据范围&#xff0c;这是一道模板的高精度乘以低精度问题。 题意是double 类型 d 与…
最新文章