C++中基于Crt的内存泄漏检测

2023-05-16

尽管这个概念已经让人说滥了 ,还是想简单记录一下, 以备以后查询。

#ifdef _DEBUG
#define  DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define  DEBUG_CLIENTBLOCK
#endif
#define  _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define  new DEBUG_CLIENTBLOCK
#endif


int  _tmain( int  argc, _TCHAR* argv[])
{
     char * p =  new  char ();
     char * pp =  new  char [10];
     char * ppp = ( char *)malloc(10);

    _CrtDumpMemoryLeaks();

     return  0;
}

主要原理是运用Crt 的内存调试功能, 通过宏替代默认的operator new, 让它被下面版本替代:
void  *__CRTDECL  operator  new (
        size_t cb,
         int  nBlockUse,
         const  char  * szFileName,
         int  nLine
        )
        _THROW1(_STD bad_alloc)
{
     /*  _nh_malloc_dbg already calls _heap_alloc_dbg in a loop and calls _callnewh
       if the allocation fails. If _callnewh returns (very likely because no
       new handlers have been installed by the user), _nh_malloc_dbg returns NULL.
     
*/
     void  *res = _nh_malloc_dbg( cb, 1, nBlockUse, szFileName, nLine );

    RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0));

     /*  if the allocation fails, we throw std::bad_alloc  */
     if  (res == 0)
    {
         static  const  std::bad_alloc nomem;
        _RAISE(nomem);
    }

     return  res;
}
这样Crt会把此次分配内存的文件名和行号以及大小等记录下来,最后当调用用 _CrtDumpMemoryLeaks();  时如果还没释放就会打印出来。
结果如下:
Detected memory leaks!
Dumping objects ->
f:\test\memleakchecker\memleakchecker\memleakchecker.cpp(23) : {108} normal block at 0x0003A1A8, 10 bytes  long .
 Data: <          > CD CD CD CD CD CD CD CD CD CD 
f:\test\memleakchecker\memleakchecker\memleakchecker.cpp(22) : {107} client block at 0x0003A160, subtype 0, 10 bytes  long .
 Data: <          > CD CD CD CD CD CD CD CD CD CD 
f:\test\memleakchecker\memleakchecker\memleakchecker.cpp(21) : {106} client block at 0x0003A120, subtype 0, 1 bytes  long .
 Data: < > 00 
Object dump complete.

下面是一些注意事项:
(1)  #define  _CRTDBG_MAP_ALLOC 的作用
如果不定义这个宏, C方式的malloc泄露不会被记录下来。

(2)数字 { 108 } {107}的作用
表示第几次分配, 你可以通过 _CrtSetBreakAlloc程序运行到预定次数时暂停  ,比如
int  _tmain( int  argc, _TCHAR* argv[])
{
    _CrtSetBreakAlloc(108);

     char * p =  new  char ();
     char * pp =  new  char [10];
     char * ppp = ( char *)malloc(10);

    _CrtDumpMemoryLeaks();

     return  0;
}

(3)如果程序有多个出口或是有涉及到全局变量, 可以通过 _CrtSetDbgFlag  设置标志让程序退出时自动打印泄露 , 比如
int  _tmain( int  argc, _TCHAR* argv[])
{
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

     char * p =  new  char ();
     char * pp =  new  char [10];
     char * ppp = ( char *)malloc(10);

     return  0;
}

(4)我们知道宏替代是最粗暴的方式, 所以尽量把下面new的替代宏放到每个Cpp里而不是放到一个通用的头文件中, 实际上MFC也是这么做的
#ifdef _DEBUG
#define  new DEBUG_CLIENTBLOCK
#endif

(5)上面的operator new只能照顾到最普通的new, 实际上operator new是有任意多种重载方式, 只需要确保第一个参数是表示大小。 比如下面的placement new就会编译失败, 因为宏替代后格式不符合要求了, 所以如果你的CPP用了非标准的new, 就不要加入new的检测宏了。
#include < new >

#ifdef _DEBUG
#define  DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define  DEBUG_CLIENTBLOCK
#endif
#define  _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define  new DEBUG_CLIENTBLOCK
#endif


int  _tmain( int  argc, _TCHAR* argv[])
{
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

     char * p =  new  char ();
     char * pp =  new  char [10];
     char * ppp = ( char *)malloc(10);

     char  d;
     char *  p1  =  new ( & d)  char ( ' a ' );

     return  0;
}

(6)因为STL里map内的tree用到了placement new,  所以如果你这样用会编译失败:
#ifdef _DEBUG
#define  DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define  DEBUG_CLIENTBLOCK
#endif
#define  _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define  new DEBUG_CLIENTBLOCK
#endif

#include <map>
你应该把  #include  < map >放到 宏定义的前面。

(7) 如果你在宏  #define  new DEBUG_CLIENTBLOCK 之后再声明或定义 operator new函数, 都会因为宏替代而编译失败。
而STL的xdebug文件恰恰申明了operator new函数, 所以请确保new的替代宏放在所有include头文件的最后, 尤其要放在STL头文件的后面。
//MyClass.cpp
#include "myclass.h"
#include <map>
#include <algorithm>

#ifdef _DEBUG
#define  new DEBUG_CLIENTBLOCK
#endif

MyClass::MyClass()
{
    char* p = new char('a');
}

(8)如果你觉得上面的这种new替代宏分散在各个CPP里太麻烦, 想把所有的东西放到一个通用头文件里,请参考下面定义的方式:
// MemLeakChecker.h 
#include <map>
#include <algorithm>
// other STL file

#ifdef _DEBUG
#define  DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define  DEBUG_CLIENTBLOCK
#endif
#define  _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define  new DEBUG_CLIENTBLOCK
#endif
 
(9)简单判断某个独立函数有没有内存泄露可以用下面的方法:
class  DbgMemLeak
{
    _CrtMemState m_checkpoint;

public :
     explicit  DbgMemLeak() 
    {   
        _CrtMemCheckpoint(&m_checkpoint); 
    };

    ~DbgMemLeak()
    {
        _CrtMemState checkpoint;
        _CrtMemCheckpoint(&checkpoint);
        _CrtMemState diff;
        _CrtMemDifference(&diff, &m_checkpoint, &checkpoint);
        _CrtMemDumpStatistics(&diff);
        _CrtMemDumpAllObjectsSince(&diff);
    };
};


int  _tmain( int  argc, _TCHAR* argv[])
{
    DbgMemLeak check;
    {
         char * p =  new  char ();
         char * pp =  new  char [10];
         char * ppp = ( char *)malloc(10);
    }

     return  0;
}

 

 (10) 其实知道了原理, 自己写一套C++内存泄露检测也不难, 主要是重载operator new和operator delete, 可以把每次内存分配情况都记录在一个Map里, delete时删除记录, 最后程序退出时把map里没有delete的打印出来。 当然我们知道Crt在实现new时一般实际上调的是malloc, 而malloc可能又是调HeapAlloc,而HeapAlloc可能又是调用RtlAllocateHeap, 所以理论上我们可以在这些函数的任意一层拦截和记录。但是如果你要实现自己的跨平台内存泄露检测,还是重载operator new吧。

 

转载于:https://www.cnblogs.com/weiym/archive/2013/02/25/2932810.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中基于Crt的内存泄漏检测 的相关文章

  • 【docker】查看docker容器或镜像的详细信息命令,查看docker中正在运行的容器的挂载位置...

    命令 xff1a docker inspect f257d69e0035 格式 xff1a docker inspect 容积或镜像ID 首先 xff0c docker ps获取简要信息 然后输入命令docker inspect f257d
  • C项目实践之通讯录管理案例

    1 功能需求分析 通讯录管理案例主要实现对联系人的信息进行添加 显示 查找 删除 更新和保存功能 主要功能需求描述如下 xff1a xff08 1 xff09 系统主控平台 xff1a 充许用户选择想要进行的操作 xff0c 包括添加联系人
  • 开源自主导航小车MickX4(十)总结

    开源自主导航小车MickX4 xff08 十 xff09 总结 1 博客回顾2 存在问题3 学习建议4 后续计划 在 开源自主导航小车MickX4 这个系列教程中 xff0c 我们一共分为了十个博客部分进行了讲解差速小车的导航 由于一些的原
  • iOS 什么是函数式编程

    前言 xff1a 当前只做理解性的常规背书 xff0c 根据不断深入学习会不断丰富解读内容 xff0c 欢迎评论提意见 函数式编程 xff1a Functional Programming 1 基本解释 xff1a 函数式编程 是一种思维模
  • MVC笔记 MVC注意事项及优化

    一 学习MVC注意事项 1 了解不同的项目类型 从ASP NET 2 0开始 xff0c vs针对网站开发区分了两种项目类型 xff0c 一种是 39 项目 39 xff08 Website Project xff09 另一种是 39 网址
  • 微软:新Windows设备需要默认支持TPM 2.0安全功能

    在Windows 10系统中微软已经做出大量调整来提升安全性能 xff0c 而现在微软进一步提升运行最新操作系统设备的安全等级 自今年夏天开始 xff0c 微软表示需要所有Windows 10设备都默认支持TPM 2 0 可信任安全平台模组
  • 令牌桶算法限流

    限流 限流是对某一时间窗口内的请求数进行限制 xff0c 保持系统的可用性和稳定性 xff0c 防止因流量暴增而导致的系统运行缓慢或宕机 常用的限流算法有令牌桶和和漏桶 xff0c 而Google开源项目Guava中的RateLimiter
  • 关机一直显示正在关闭服务器,电脑关机后,显示正在关机,但等半天也关不了 怎么办...

    电脑关机后 xff0c 显示正在关机 xff0c 但等半天也关不了 怎么办以下文字资料是由 历史新知网www lishixinzhi com 小编为大家搜集整理后发布的内容 xff0c 让我们赶快一起来看一下吧 xff01 电脑关机后 xf
  • 一只老鸟嵌入式工程师的血泪史!

    作为一名在嵌入式行业摸爬滚打许久的老鸟 xff0c 回想自己的经历之路 xff0c 那么漫长可又仿佛近在眼前 随着学生的日益增多 xff0c 偶尔之间 xff0c 会想起自己曾经的一个经历 此文仅献给那些刚刚踏上硬件之路和还在徘徊的同学们
  • 程序员的“菜鸟心态综合症”

    第3章 程序员的 菜鸟心态综合症 清华大学出版社 Java程序员 xff0c 上班那点事儿 作者 xff1a 钟声 第3章部分节选 人的一生会遇到很多挫折 xff0c 尤其是我们刚刚参加工作初期的年轻人 这个人生阶段往往会出现各种各样的处世
  • sc.textFile("file:///home/spark/data.txt") Input path does not exist解决方法——submit 加参数 --master local...

    use this val data 61 sc textFile 34 home spark data txt 34 this should work and set master as local Input path does not
  • mongodb查询数据库中某个字段中的值包含某个字符串的方法

    正则表达式最能解决 xff1a 例如 xff1a db getCollection 39 news 39 find 39 content 39 120 77 215 34 9999 这里主要是注意正则表达式要写对 xff0c 该转义的注意转
  • MATLAB 求两个矩阵的 欧氏距离

    欧式距离定义 xff1a 欧式距离公式有如下几种表示方法 xff1a MATLAB 求两个矩阵的 欧氏距离 xff1a 如果定义两个矩阵分别为a b 则定义c 61 a b 2 所求距离d 61 sqrt sum c
  • Vmware虚拟机磁盘空间不足

    Vmware虚拟机清理磁盘空间 遇到一个问题就是虚拟机中的磁盘空间越来越小 xff0c 即使把文件删除以后 xff0c 磁盘空间还是无法释放 这主要是vmware中的缓存没有清除 在使用vmware虚拟机的时候 xff0c 经常会在主机和虚
  • 技术面试感觉什么都会,面试官一问回答不上来怎么办?

    又到了一年金三银四 xff0c 回想到很多年前我刚参加工作时的面试经历 xff0c 那时都是呆呆地等着面试官问问题 xff0c 被问到一些自己并不熟悉的问题时要不就是思考半天也切不中要点 xff0c 要不就只能无奈地回答并不清楚了 其实不管
  • 强化学习遭遇瓶颈!分层RL将成为突破的希望

    本文作者是法国里尔大学Inria SequeL团队的博士生 xff0c Yannis Flet Berliac xff0c 他在本文中对分层强化学习 xff08 HRL xff09 的研究进行了总结 xff0c 文章首先回顾了强化学习 xf
  • 如何免费下载百度文库文章的三种方法

    百度文库中的资源很丰富 xff0c 但那里的文章不能复制 xff0c 而且有的要下载币 给 大家总结下免费下载复制百度文库的三种方法 第一种 利用百度快照 我们在百度文库中找到自己想要的文章后 xff0c 直接把那篇文章的地址复制 xff0
  • 434个H5游戏源码

    各种类型HTML5游戏 xff0c 界面和JS均可供项目参考 下面是下载地址 转载于 https blog 51cto com 12130120 2374590
  • iOS 左右滑动 手势 响应方法

    1 64 property nonatomic strong UISwipeGestureRecognizer leftSwipeGestureRecognizer 64 property nonatomic strong UISwipeG
  • 一道c语言编程题

    一道c语言编程题 将一个5 5的矩阵中最大的元素放在中心 xff0c 四个角分别放四个最小的元素 xff08 顺序从左到右 xff0c 从上到下顺序依次从小到大存放 xff09 xff0c 写一函数实现之 xff0c 用main函数调用 i

随机推荐

  • print(1,2,3,sep=':')的输出结果是?

    print 1 2 3 sep 61 39 39 1 2 3 第一个参数 要打印的值 第二个参数sep表示要打印多个值时 各值的分割方式 默认空格 第三个参数end表示结尾的方式 默认 n 转载于 https www cnblogs com
  • S3. Android 消息推送

    概要 消息推送 转载于 https www cnblogs com zlxyt p 11133181 html
  • Android camera2 回调imagereader 从Image拿到YUV数据转化成RGB,生成bitmap并保存

    ImageUtil java import android graphics ImageFormat import android media Image import android os Build import android sup
  • C语言中字符串结束符'\0'

    本质 39 0 39 就是8位的00000000 xff0c 因为字符类型中并没有对应的这个字符 xff0c 所以这么写 39 0 39 就是 字符串结束标志 39 0 39 是转义字符 xff0c 意思是告诉编译器 xff0c 这不是字符
  • SLAM中双目三角化

    双目三角化 形式1 xff1a 在等式左边同时乘 x 1 x 1 x 1 和
  • 用手机对电脑进行远程关机

    PS 本人一月份写的文章 xff0c 贴在这里 昨天真是奔波的一天 xff0c 中午烤肉逛街下午寿司看电影 xff08 陪老婆 xff09 今天中午又是麻辣诱惑 额 xff0c 不争气的肠胃果然导致我拉肚子了 不过 xff0c 话说昨天下午
  • 程序员到底是一个什么职业?

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 程序员首先是雇员 然后是工程师 xff1b 比起创造力 xff0c 工程能力对这个职位更为重要 为什么有人在技术造神 大家应该已经感受到 xff0c 技术圈这两年已经和娱乐
  • android 清理内存杀死service,关于Service常驻内存不被清理的解决方法.

    众所周知 Service是跑后台的 但是有些Rom厂商把一键清理做的真是太好用了 以至于一键清理变成了一种习惯 Service已经变的不再是Service了 那为什么像诸如360 微信 QQ 却可以傍山傍水 哦 用错词了 大家懂的 言归正传
  • 自主做一个类似于微博的项目(计划篇)

    项目名称 xff1a archou微博 项目架构 xff1a B S架构 项目开发语言 xff1a java jquery html hql 开发框架 xff1a spring mvc hibernate 开发平台 xff1a window
  • [工作记录] 点云线特征提取

    概述 目前的点云线特征提取方法可以分为 xff1a 1 基于面片patch的线特征提取 xff0c 主要可以提取交线 xff0c 边缘线 这类方法首先都是要提取面 xff0c 然后对每个面对象提取 又可以分为 xff1a 基于图像的提取 x
  • Javascript闭包:从理论到实现,[[Scopes]]的每一根毛都看得清清楚楚

    昨天我写到 所有Javascript函数都是闭包 xff0c 有些同学表示还是接受不能 我好好的一个函数 xff0c 怎么就成闭包了 xff1f 那么 xff0c 让我们来探究一下 xff0c Chrome xff08 V8 xff09 到
  • mysql5.7安装审计插件libaudit_plugin.so

    1 下载插件 https bintray com mcafee mysql audit plugin release 1 1 7 805 files 2 解压插件复制到mysql lib库插件目录下 xff1a unzip audit pl
  • 通过jdbc连接hive报java.sql.SQLException: Method not supported问题

    今天尝试通过jdbc连接hive xff0c JDBC直接连接是正常成功的 xff0c 实例 xff1a import java sql Connection import java sql DriverManager import jav
  • DHCP介绍及H3C配置DHCP

    1 DHCP引入 1 简介 DHCP xff08 动态主机设置协议 xff09 是一个局域网的网络协议 xff0c 使用UDP协议工作 xff0c 主要作用是集中的管理 分配IP地址 xff0c 使网络环境中的主机动态的获得IP地址 Gat
  • centos7-内核版本降级

    环境介绍 线上环境运行centos 内核版本规定为 xff1a CentOS Linux release 7 3 1611 Core 查看内核版本参考命令 xff1a root 64 localhost cat etc redhat rel
  • SLAM中多目三角化

    多目三角化 1 闭式求解1 1 DLT 最小二乘方法求解1 2 最小化3D距离 2 构建优化方法求解3 构建高斯深度滤波器 LSD SLAM4 构建Beta分布滤波器 SVO5 EKF SLAM参考资料 在能实现双目计算特征点的深度基础上
  • 微软操作系统 Windows Server 2012 R2 官方原版镜像

    微软操作系统 Windows Server 2012 R2 官方原版镜像 Windows Server 2012 R2 是由微软公司 xff08 Microsoft xff09 设计开发的新一代的服务器专属操作系统 xff0c 其核心版本号
  • 最近很忙,也很累,忙里偷闲,尝试了下apache solr的安装

    最近很忙 xff0c 也很累 xff0c 忙里偷闲 xff0c 尝试了下apache solr的安装 第一次接触java的 xff0c 就和初次安装NET一样 部署开发环境折腾来折腾去 几经波折总算成功了 分享下个人安装的过程 xff1a
  • "类工厂模式"改写SqlHelper

    看到标题您一定很疑惑 xff0c 23种经典设计模式什么时候多了一个 34 类工厂模式 34 稍等 xff0c 请听我慢慢道来 实践是检验真理的唯一途径 最近用了 34 类工厂模式 34 改写了我公司的SqlHelper类 xff0c 改写
  • C++中基于Crt的内存泄漏检测

    尽管这个概念已经让人说滥了 xff0c 还是想简单记录一下 xff0c 以备以后查询 ifdef DEBUG define DEBUG CLIENTBLOCK new CLIENT BLOCK FILE LINE else define D