c++中内存分配/释放与内存泄漏检测小结

编程知识 更新时间:2023-04-18 19:08:22

一、c++内存分配和释放

1、在c语言中,我们常使用malloc/free的方法来分配和释放内存,如下:

       #include <stdlib.h>

       void *malloc(size_t size);
       void free(void *ptr);
       void *calloc(size_t nmemb, size_t size);
       void *realloc(void *ptr, size_t size);
       void *reallocarray(void *ptr, size_t nmemb, size_t size);

       Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       reallocarray():

或者: 

#include <iostream>
#include <stdlib.h>

typedef int* pint;
using std::cout;
using std::endl;

int main(int argc,char* argv[])
{
	//!  [1] allocates size bytes and returns a pointer to the allocated memory
	pint p = (pint)malloc(sizeof(int)); // 分配内存但不会初始化
	if(NULL == p ){
		cout << "error occured." << endl;
		return -1;
	}

	*p = 1;
	cout << "0x" << p << " [vaule]:" << *p << endl;

	free(p);
	p = NULL;


	//! [2] allocates memory for an array of nmem elements type of int
	size_t nmem = 4;
	pint p_arr = (pint)calloc(nmem,sizeof(int)); // 分配内存并初始化
	if(NULL == p_arr ){
		cout << "error occured." << endl;
		return -1;
	}

	for(int i = 0 ; i < nmem;++i){
		*(p_arr+i) = i*3;
	}

	for(int i = 0 ; i < nmem;++i){
		cout << "calloc index:" << i << " [value]:"<<  *(p_arr+i) << endl;
	}
	
	free(p_arr);
	p_arr = NULL;

	getchar();
	return 0;
}

2、在c++中,我们则常用new /delete 的方法来申请分配和释放内存

#include <iostream>
#include <string>

using std::cout;
using std::endl;
typedef int* pint;

int main(int argc,char* argv[])
{
	//! [1] allocated memory for var
	pint num = new int(2); // 为变量num分配内存并初始化为2
	if(NULL == num){
		cout << "allocated memory failed." << endl;
		return -1;
	}
	cout << "0x" << num << "  [val]:" << *num << endl;

	delete num;  // 释放内存
	num = NULL;

	//! [2] allocated memory for arrary
	pint num_arr = new int[2]();  // 为数组分配内存,并默认初始化
	for(int i = 0; i < 2;++i){
		cout << num_arr[i] << endl;
	}
	delete[] num_arr;
	num_arr = NULL;

	getchar();
	return 0;
}

顺便总结下,C语言中的malloc和C++中的new有什么区别?

 

new / deletemalloc /  free
new、delete是操作符,可以重载,只能在C++中使用malloc、free是函数,可以覆盖,C、C++中都可以使用
new可以调用对象的构造函数,delete调用相应的析构函数malloc 仅仅分配内存,free仅收回内存
new 和delete 返回的是数据类型的指针;malloc和free返回的是void类型指针

二、内存泄漏怎么调试?

       1、调试模式下的内存泄漏检测方法

           对于堆上内存操作(new,malloc)的检测,可以使用在Win32平台使用_CrtDumpMemoryLeaks()函数对内存泄露进行检测  

#include <iostream>
#include <stdlib.h>
#include <crtdbg.h>

using std::cout;
using std::endl;

#define _CRTDBG_MAP_ALLOC
#define My_new new(_NORMAL_BLOCK, __FILE__, __LINE__)	

int main(int argc, char* argv[])
{
	system("color f0");
	_CrtMemState Sh1, Sh2, Sh_Diff;
	
	int *p_array = My_new int[10];
	_CrtMemCheckpoint(&Sh1);					//设置第一个内存检查点

	//delete[] p_array;
	//p_array = NULL;

	_CrtMemCheckpoint(&Sh2);					//设置第二个内存检查点
	_CrtMemDifference(&Sh_Diff, &Sh1, &Sh2);	//检查变化
	_CrtMemDumpAllObjectsSince(&Sh_Diff);		//Dump变化

	_CrtDumpMemoryLeaks();	                    //检测内存泄露
 
	system("pause");
	return 0;
}

或者: 

#include <cstdio>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <crtdbg.h>

#define _CRTDBG_MAP_ALLOC
using namespace std;

#define My_new new(_NORMAL_BLOCK, __FILE__, __LINE__)	//自定义new

int main(int argc, char* argv[])
{
	_CrtSetBreakAlloc(233);

	int *p = My_new int[2];
	for(int i = 0 ;i < 2;i++){
		*(p+i) = i;
		cout << *(p+i) << endl;
	}

	//delete[] p;
	//p = NULL;

	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	return 0;
}

 参考

(1) https://wwwblogs/lidabo/p/14381699.html

(2) https://blog.csdn/m_buddy/article/details/74356721

 

  2、生产状态(运行模式)下内存泄漏检测 ==》基于windbug 工具

2.1、使用windbg中的umdh检查

2.1.1、 工具下载

下载地址:http://www.technlg/windows/windgb-download/
根据计算机系统,确定下载x64或者x86版本

2.1.2、环境变量配置

计算机-》右击-》属性-》高级系统设置-》环境-》系统变量-》Path-》编辑-》变量值 处后加入:

c:\Program Files\Debugging Tools for Windows(x64)

2.1.3、利用工具umdh(user-mode dump heap)分析

(1)由于在安装路径下有 gflags.exe、umdh.exe 这两个可执行文件,且在步骤2中已加入环境变量,下一步可直接在dos界面输入命令;

(2)桌面左下角-》开始 处输入cmd命令,打开dos界面窗口后,输入命令:gflags.exe,会出现下图,并按照下图进行相关设置:


(3)gflags标志设置好后,开启cmd

键入要定位内存泄露的程序gflags.exe /I memroyleak.exe(程序名称)+ust
如图成功后,开启memoryleak.exe程序,即运行需要测试的程序。

2.1.4、利用umdh创建heap快照


命令格式:umdh –pn:memoryleak.exe(程序名称) –f:snap1.log(日志名称)
程序运行一段时间后或者程序占用内存增加时,将memoryleak.exe退出。
然后再次创建heap快照,命令行无差别,snap1.log改为snap2.log或者其他。

设置好程序的符号路径,如下图:

设置好后可以开始分析heap前后两个快照的差异

分析差异命令:umdh –d snap1.log snap2.log –f:result.txt

分析完成后查看结果result.txt,可以指定具体的输出文件夹,不指定的话,输出在桌面的个人文件夹《以自己名字命名的文件夹》

红色为umdh定位出来的泄露点,我们在查看源代码

这样我们就可以修改代码中内存泄露的地方了。

注意:利用Umdh创建Heap快照 步骤设置程序的符号路径,此符号路径是一个在线网址,因此需要电脑联网;对于我们来说只能通过下载符号离线包的方式,离线包的路径为:

https://developer.microsoft/en-us/windows/hardware/download-symbols

关键词:Download Windows Symbol Packages

但是不下载此包,符号路径会自动设置为 %windir%\symbols 即windows自带的符号路径,目前未发现问题

参考网址:http://blog.csdn/chenyujing1234/article/details/11918987

2、使用windbg中的htrace检查

2.1、准备工作

1 打开windbg
2 File->Symbol File Path,配置好符号文件(PDB)

3 File->Attache to a Process->可以选择一个运行中的进程,并对其进行调试。

2.2、快照

1 让程序运行(按F5或输入命令:g)
2 程序执行到想要快照的时候,中断程序(Debug->Break)
3 开启句柄栈回溯(输入命令:!htrace -enable)
4 抓取快照(输入命令:!htrace -snapshot)

2.3 、执行操作,比较差异

1 让程序运行(按F5或输入命令:g)
2 执行操作
3 中断程序(Debug->Break)
4 !htrace -diff

2.4、找到代码行

(1) 查看泄漏的句柄
从下图中可以看出有一个句柄泄漏,该句柄时通过CreateEvent创建出来的事件,通过栈回溯可以看出该事件创建事件的函数:vlc_tester::on_pB_Open_clicked。

(2) 查找具体的代码行
lsa vlc_tester!vlc_tester::on_pB_Open_clicked+0x000000000000002c
从下图中可以看出具体的代码。

(3) 如果在栈回溯中看不到有用信息,还可以考虑在代码中打印出线程ID,再与句柄泄漏所在线程对比,确认在哪个线程泄漏的,缩小范围。
(4) 根据栈回溯的模块或模块地址也能找到是哪个模块泄漏的句柄。

2.5、Process Explorer

Process Explorer
1 显示句柄详细信息

2 查看程序占用的句柄,如果是命名句柄,可以可以直接在代码中找到该句柄

参考网址:https://www.jianshu/p/3c88d5adc7bc

 

更多关于windbg的调试和使用方法,可以参考MSDN。

https://docs.microsoft/zh-cn/windows-hardware/drivers/debugger/

 


 

 

更多推荐

c++中内存分配/释放与内存泄漏检测小结

本文发布于:2023-04-14 18:31:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/e3d4ee7066dcebe5df8c9ddb08982a12.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:内存   小结   分配

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 76884文章数
  • 14阅读数
  • 0评论数