一、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 / delete | malloc / 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++中内存分配/释放与内存泄漏检测小结
发布评论