百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

windows下C++内存泄漏检测和dump文件生成

lipiwang 2025-03-25 15:04 12 浏览 0 评论

前言

写c++的程序员都应该对申请内存和释放内存有着深刻的领悟(可能有些初级用着前人封装的智能指针感受不深)。同时对于出现崩溃生成可以调试的dump文件也极为重要,对于win下的发布版程序很重要。

工具

crtdbg侦测内存泄露,dbghelp 生产minidump

内存泄漏是在vs开发中,程序结束在vs输出里面会提示有没有内存泄露。dump文件是在程序运行工程中崩溃时候捕捉异常后生成的,要配合对应的pdb文件和代码用vs进行分析。

实例

样例中的 memorytools.cpp memorytools.h 可以直接拿过去用的,不需要额外引用头文件和库。

代码目录:

├── main.cpp
├── memorytools.cpp (附在文章后面面)
└──memorytools.h(附在文章后面面)

1.内存泄漏检测

main.cpp

#include "memorytools.h"
int main()
{
  //设置生成dump文件名
	lge::CMemoryTools::initAppName("test");
	//初始化
	lge::CMemoryTools::initDebug();
	//测试内存泄露
	char * p = (char*) malloc(1000);
	int* pInt = new int;
	return 0;
}

运行后提示如下:


如果申请的内存,在程序退出后还没有释放,会提示你内存泄漏。当然很多项目用的单例,在程序关闭的时候,不释放一样会提示内存泄漏。

如果想知道内存是哪一步申请的,比如我圆圈圈出的63,可以直接在CMemoryTools::initDebug函数内将_CrtSetBreakAlloc(0); 改成 _CrtSetBreakAlloc(63); 这种vs在调试的时候,就会自动断点到这步的内存申请(但对于大项目这种方式其实不适用)。

2.dump生成及调试

#include "memorytools.h"
class CTest
{
public:
	int p;
};
int main()
{
  //设置生成dump文件名
	lge::CMemoryTools::initAppName("test");
	//初始化
	lge::CMemoryTools::initDebug();
	//测试崩溃
	CTest* pTest = NULL;
	pTest->p = 1;
	return 0;
}

在exe所在目录直接双击打开,会看到生成的dump文件。

保障exe pdb 和代码都是对应的关系,将dmp文件直接拖进vs项目即可。

之后就可以直接调试了。

memorytools.h

#pragma once

#if WIN32
#include 
#include 
#pragma warning(disable:4091)
#pragma comment(lib,"Dbghelp.lib")
#include 
#include  
#include 
#include 
#include 

#ifdef DEBUG
#   ifdef _MSC_VER
#       ifndef _CRTDBG_MAP_ALLOC
#           define _CRTDBG_MAP_ALLOC
#       endif
#ifndef _MAPNEW
#define _MAPNEW
#endif
#       ifdef _MAPNEW
#           ifndef _CRTDBG_MAP_ALLOC_NEW
#               define _CRTDBG_MAP_ALLOC_NEW
#           endif
#       endif
#       include 
#       ifdef _MAPNEW
#           ifndef new
#               define DEBUG_NORMALBLOCK new(_NORMAL_BLOCK, __FILE__, __LINE__)
#               define new DEBUG_NORMALBLOCK
#           endif
#       endif
#   endif
#endif

#ifndef __FILE_LINE__
#   define	_TLN(LN)		#LN
#   define	__TLINE__(LN)	_TLN(LN)
#   define	__FILE_LINE__	__FILE__"("__TLINE__(__LINE__)")"
#endif
#define APP_NAME_TYPE CString	
#else
#define	APP_NAME_TYPE std::string
#endif

namespace lge
{
	/*
	*	windows下内存泄漏检测工具
	*/
	class CMemoryTools
	{
	public:
		static void initAppName(const APP_NAME_TYPE& name);

		static void initDebug();

		static APP_NAME_TYPE __app_name__;
		
		static bool _initDebug;
	};
}

memorytools.cpp

#include "memorytools.h"
APP_NAME_TYPE lge::CMemoryTools::__app_name__ = "engine";

bool lge::CMemoryTools::_initDebug = false;

#if WIN32
int MemoryLeakReportRoutine(int blockType, char *message, int *p)
{
	if (strcmp(message, "Object dump complete.\n") == 0)
	{
		static const char * szSolvMemLeak = "请解决内存泄露!\r\n";
		OutputDebugStringA(szSolvMemLeak);
	}
	return 0;
}

LONG WINAPI UnhandleExceptionFilte(EXCEPTION_POINTERS *ExceptionInfo)
{
	SYSTEMTIME Systime;
	GetLocalTime(&Systime);
	CString Str;
	Str.Format(_T("%s_%d-%d-%d-%02d-%02d-%02d.dmp"), lge::CMemoryTools::__app_name__, Systime.wYear, Systime.wMonth, Systime.wDay, Systime.wHour, Systime.wMinute, Systime.wSecond);
	HANDLE	hFile = CreateFile(Str, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
	MINIDUMP_TYPE wDumpFlag = MiniDumpWithFullMemory;
	if (hFile != INVALID_HANDLE_VALUE)
	{
		MINIDUMP_EXCEPTION_INFORMATION ExInfo;
		ExInfo.ThreadId = GetCurrentThreadId();
		ExInfo.ExceptionPointers = ExceptionInfo;
		ExInfo.ClientPointers = NULL;
		MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
			hFile, wDumpFlag, &ExInfo, NULL, NULL);
		CloseHandle(hFile);
	}
	ExitProcess(-1);
	return 0;
}
#endif	//WIN32

void lge::CMemoryTools::initAppName(const APP_NAME_TYPE& name)
{
	__app_name__ = name;
}

void lge::CMemoryTools::initDebug()
{
	if (_initDebug)
	{
		return;
	}
	_initDebug = true;
#ifdef WIN32
#ifdef DEBUG
	_set_error_mode(_OUT_TO_MSGBOX);
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
	_CrtSetReportHook(&MemoryLeakReportRoutine);
	_CrtSetBreakAlloc(0);
#endif // DEBUG
	SetUnhandledExceptionFilter(UnhandleExceptionFilte);
#endif
}


相关推荐

Qwen上新AI前端工程师!一句话搞定HTML/CSS/JS,秒变React大神

梦晨发自凹非寺量子位|公众号QbitAIQwen上新“AI前端工程师”WebDev,一句话开发网页应用。三大件HTML,CSS,JavaScript一个工具全包了,定睛一看用的还是Reac...

程序员的 JavaScript 代码该如何让计算机搞懂?

出自程序员之手的JavaScript代码,该如何变成计算机所能理解的机器语言呢?本文将带你走进JavaScript引擎内部,一探究竟。作者|LydiaHallie译者|弯月,责编|...

JavaScript:如何优雅的创建数组?

在JavaScript里,有多种方式可以创建数组,下面为你详细介绍:1.使用数组字面量这是最常用的创建数组的方法,使用方括号[]来创建数组。//创建一个空数组letemptyArray...

Jquery 详细用法

1、jQuery介绍(1)jQuery是什么?是一个js框架,其主要思想是利用jQuery提供的选择器查找要操作的节点,然后将找到的节点封装成一个jQuery对象。封装成jQuery对象的目的有...

HTML页面基本结构和加载过程

大家好,我是皮皮。前言对于前端来说,HTML都是最基础的内容。今天,我们来了解一下HTML和网页有什么关系,以及与DOM有什么不同。通过本讲内容,你将掌握浏览器是怎么处理HTML内容的,...

【HarmonyOS Next之旅】兼容JS的类Web开发(一)

目录1->概述1.1->整体架构2->文件组织2.1->目录结构2.2->文件访问规则2.3->媒体文件格式3->js标签配置3....

JavaScript初学者指南

如果你刚接触JavaScript,想必已经被“modulebundlersvs.moduleloaders”、“Webpackvs.Browserify”和“AMDvs.Common...

前端图片延迟加载详细讲解

原文链接:http://www.gbtags.com/gb/share/6366.htm?原本是打算昨天昨天下午的时候就写一篇关于前端图片延迟加载的详细技术的博客的,没想到下午公司项目出现了一些问题...

selenium:操作滚动条的方法(8)

selenium支持几种操作滚动条的方法,主要介绍如下:使用ActionChains类模拟鼠标滚轮操作使用函数ActionChains.send_keys发送按键Keys.PAGE_DOWN往下滑动...

jQuery 获取和设置HTML元素

jQuery中包含更改和操作HTML元素和属性的强大方法。我们可以通过这些方法来获取HTML元素中的文本内容、元素内容(例如HTML标签)、属性值等。text()方法text()方法可以用...

JavaScript脚本如何断言select下拉框的元素内容?

使用JavaScript脚本断言select下拉框的元素内容,需要考虑页面元素是否加载成功,出错时打印等,主要实现功能功能需包括如下几点:1.等待下拉框元素加载完成(支持超时设置)2.获取下...

JavaScript图片或者div拖动拖动函数的实现

/**拖动图片封装html格式:<imglay-src="${item.Resourcesurl}"alt="${item.ResourcesName}"...

JavaScript代码怎样引入到HTML中?

JavaScript程序不能独立运行,它需要被嵌入HTML中,然后浏览器才能执行JavaScript代码。通过<script>标签将JavaScript代码引入到HTM...

当你在Vue.js中想要隐藏 `` 标签时,可以这样做:

在Vue.js里,要是你想要搞掉`<br>`(换行)标签的效果,通常有几种路子:1.使用CSS嗯,最简单的办法就是用CSS搞定,控制元素的样式,让<br>标签彻底不显示...

php手把手教你做网站(三十)上传图片生成缩略图

三种方法:按比例缩小、图片裁切、预览图片裁切不管使用哪一个都是建立在图片已经上传的基础上;预览裁切上传,如果预览的图片就是原始大小,可以预览裁切以后上传(这里是个假象,下边会说明);1、上传以后按比例...

取消回复欢迎 发表评论: