忘记释放已经分配的内存是一种常见的编程错误,当然我指的是在C++编程当中,例如下面的代码里面就存在一个忘记释放内存的编程错误。我个人觉得忘记释放内存的编程错误是不可避免的,毕竟程序员都是人,困了,心情不好了,代码过于复杂啦等等都可能导致忘记加上一句delete XXX语句。

#include <tchar.h>
#include <windows.h>
#include <string>
#include <iostream>
using namespace std;class CTestClass
{
public:CTestClass(LPWSTR szName){m_lpName = new wstring(szName);}~CTestClass(){}void PrintName(){wcout << *m_lpName << endl;}
private:wstring *m_lpName;
};
HRESULT CreateTestClass(LPWSTR szName, CTestClass **ppObject)
{*ppObject = new CTestClass(szName);if ((*ppObject) == NULL)return E_FAIL;elsereturn S_OK;
}
int _tmain(int argc, _TCHAR* argv[])
{CTestClass *pObject = NULL;HRESULT hr = CreateTestClass(L"This is a Test", &pObject);if (hr != S_OK){return -1;}else{pObject->PrintName();  // pObject没有被释放return 0;}
}

实际上Visual Studio已经提供了方法帮助你快速找到这些没有释放的内存。

Visual Studio提供了一系列的CRT调试API,CRT提供了一个调试内存分配堆,可以跟踪和管理内存在什么地方分配,当你在这个堆上分配内存的时候,每一次内存分配调用例如malloc或者new,CRT都会额外分配大约36个字节用来保存例如这个内存块分配的文件名、行号、内存块的大小等信息,最后CRT将这些内存块使用一个双链表链接起来。每一次内存释放的时候,free或者delete函数就从这个内存块链表里面将要释放的内存块删除,因此在需要检查内存泄漏的时候,只要遍历这个双链表依次打印出这些内存块就可以发现所有未释放的内存了。下面是CRT内存块的原始声明:

typedef struct _CrtMemBlockHeader
{// Pointer to the block allocated just before this one:struct _CrtMemBlockHeader *pBlockHeaderNext;// Pointer to the block allocated just after this one:struct _CrtMemBlockHeader *pBlockHeaderPrev;char *szFileName;    // File nameint nLine;           // Line numbersize_t nDataSize;    // Size of user blockint nBlockUse;       // Type of blocklong lRequest;       // Allocation number// Buffer just before (lower than) the user's memory:unsigned char gap[nNoMansLandSize];
} _CrtMemBlockHeader;

下面的代码演示了如何使用CRT提供的调试API来修改刚才的源文件检测未释放的内存空间(注意红色添加的部分):

#include <tchar.h>
#include <windows.h>
#include <string>
#include <iostream>
// 使用CRT调试API
#include <crtdbg.h>
using namespace std;
// 将所有的内存分配函数new替换成CRT提供的调试new
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new(_CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
class CTestClass
{
public:CTestClass(LPWSTR szName){m_lpName = new wstring(szName);}~CTestClass(){}void PrintName(){wcout << *m_lpName << endl;}
private:wstring *m_lpName;
};
HRESULT CreateTestClass(LPWSTR szName, CTestClass **ppObject)
{*ppObject = new CTestClass(szName);if ((*ppObject) == NULL)return E_FAIL;elsereturn S_OK;
}
int _tmain(int argc, _TCHAR* argv[])
{  // 设置CRT调试API的报表输出模式,将所有的错误、警告还有断言都输出到控制台_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);CTestClass *pObject = NULL;HRESULT hr = CreateTestClass(L"This is a Test", &pObject);if (hr != S_OK){return -1;}else{pObject->PrintName();// 检查未释放的内存_CrtDumpMemoryLeaks();return 0;}
}

转载于:https://www.cnblogs.com/steady/archive/2011/04/26/2029654.html

使用CRT调试内存分配堆来找出未释放的内存空间相关推荐

  1. 【Windows 逆向】使用 CE 工具挖掘关键数据内存真实地址 ( CE 找出子弹数据内存地址是临时地址 | 挖掘真实的子弹数据内存地址 )

    文章目录 一.CE 找出子弹数据内存地址是临时地址 二.挖掘真实的子弹数据内存地址 1.找出哪些指令访问了子弹数据地址 0x21160114 2.查看 0x21160114 地址是如何计算出来的 ( ...

  2. Linux fs清理文件,linux找出已经删除但磁盘空间未释放的大文件并清空

    linux找出已经删除但磁盘空间未释放的大文件并清空 1.找出已经删除但磁盘空间未释放的文件 如果文件已经删除,但实际的磁盘空间未释放,这个时候文件句柄fd相关信息还在内存中,可以通过lsof命令找出 ...

  3. linux找出已经删除但磁盘空间未释放的大文件并清空

    1.找出已经删除但磁盘空间未释放的文件 如果文件已经删除,但实际的磁盘空间未释放,这个时候文件句柄fd相关信息还在内存中,可以通过lsof命令找出,比如打开文件的pid和读写文件的系统fd. lsof ...

  4. activiti如何最后一次提交事务_MySQL如何找出未提交事务的SQL浅析

    很久之前曾经总结过一篇博客"MySQL如何找出未提交事务信息",现在看来,这篇文章中不少知识点或观点都略显肤浅,或者说不够深入,甚至说部分结论是错误的.下面重新探讨一下这个话题.那 ...

  5. mysql未提交事务sql_MySQL如何找出未提交事务的SQL浅析

    --准备测试环境数据(实验环境为MySQL 8.0.18社区版)mysql> create table kkk(id int , name varchar(12));Query OK, 0 ro ...

  6. mysql查询未提交事务_MySQL如何找出未提交事务信息

    前阵子,我写了一篇博客 , 那么在 MySQL 数据库中,我们能否找出未提交事务执行的SQL语句或未提交事务的相关信息呢? 实验验证了一下,如果一个会话(连接)里面有一个未提交事务,然后不做任何操作, ...

  7. MySQL找出未提交事务的信息

    目录 一.processlist中的未提交事务 二.information_schema.innodb_trx中的未提交事务 三.performance_schema.events_statement ...

  8. java 栈和堆 进出顺序_Java内存分配---堆与栈

    堆和栈的概念接触已久,也很容易让人似懂非懂.本文阐述它们的区别和作用.配合一个小例子,加深对其理解. 堆内存 堆内存是在Java程序运行时分配的,它用来存放对象,对象也总是在堆中.GC的作用域也是在堆 ...

  9. php 堆内存和栈内存,内存分配堆与栈的区别

    堆(Heap)与栈(Stack)是开发人员必须面对的两个概念,在理解这两个概念时,需要放到具体的场景下,因为不同场景下,堆与栈代表不同的含义.一般情况下,有两层含义: (1)程序内存布局场景下,堆与栈 ...

最新文章

  1. 兴趣点推荐代码_推荐系统模型阿里用户兴趣模型(附完整代码)
  2. oracle使用sqlplus创建表空间
  3. 卡常神器——register 与 快速读入输出
  4. 【springboot】mybatis-generator+tkmybatis通用mapper+swagge+redis缓存整合使用
  5. suse 内核编译安装_升级SUSE Linux内核的完整步骤!
  6. 用 Python 下载抖音无水印视频
  7. Java 使用SAX解析XML文档
  8. C# 调用Excel组件生成excel文件
  9. 美女在中国移动家属院上厕所
  10. ijkplayer-添加播放截图功能
  11. verilog coding style_阿里云收购长亭科技后 腾讯云也完成了对CODING的收购
  12. ubuntu编译安装vim7.4
  13. java access数据库连接_Java Access数据库连接
  14. SWAT模型学习小技巧(一)
  15. 服务器端查询客户端cookie时的拙计
  16. win10搭建openvpn以及使用
  17. 国庆活动征文 | 庆国庆,作几首打油诗在此
  18. 实现Torchlight(火炬之光)的背包UI效果
  19. RuntimeError: cannot perform reduction function max on tensor with no elements because the operation
  20. 初识数据编码,从 0 开始的进阶之路 ! ~ 内附:植物大战僵尸修改游戏存档、金币 演示~

热门文章

  1. 再次学习javascript中的參数传递
  2. [luoguP2331] [SCOI2005]最大子矩阵(DP)
  3. 数组初始化 和 vector初始化
  4. [转]关于多线程并发:每个开发人员都应了解的内容(转自Mainz's)
  5. Swift傻傻分不清楚系列(六)集合类型
  6. Java基础教程:面向对象编程[2]
  7. Linux中设置vim自动在运算符号两边加上空格
  8. 本地数据jqGrid分页
  9. 基于Google Reader发展起来的个性化推荐系统之三大问题
  10. PHP从零开始--数据库