重载全局new/delete实现内存检测
下面介绍用重载new/delete运算符的方式来实现一个简单的内存泄露检测工具,基本思想是重载全局new/delete运算符,被检测代码调用new和delete运算符时就会调用重载过的operator new和operator delete,在重载的operator new里和operator delete里记录下内存申请和释放信息,从而判断内存使用情况。
下面一步步介绍它的实现!
1、全局new/delete的重载
先看一下重载new/delete的规则:
重载的operator new的参数个数任意,但第一个参数必须是size_t类型的,返回值必须是void*。重载operator delete只允许有一个参数,且是void*型。
当然,不光要重载operator new 和 operator delete, 还要重载operator new [], operator delete [],更多operator new和operator delete重载的内容参考《Effective C++》
重载的new/delete, new[]/delete[]代码如下:
void * operator new (size_t size)
{
if(0 == size)
{
return 0;
}
void *p = malloc(size);
return p;
}
void * operator new [](size_t size)
{
return operator new(size);
}
void operator delete (void * pointer)
{
if(0 != pointer)
{
free(pointer);
}
}
void operator delete[](void * pointer)
{
operator delete(pointer);
}
2、用__FILE__, __LINE__记录new的位置
为了找到内存泄露的元凶,我要记录下每一处new所在的文件名和所在行。于是再次重载了operator new:
void * operator new (size_t size, const char* file, const size_t line);
void * operator new [](size_t size, const char* file, const size_t line);
为了避免编译时出现warning C4291(没有与operator new(unsigned int,const char *,const unsigned int) 匹配的delete),又重载了
void operator delete (void * pointer, const char* file, const size_t line);
void operator delete[](void * pointer, const char* file, const size_t line);
尽管我知道它没用①。
我想到了用系统提供的__FILE__和 __LINE__宏获取当前文件名与行号,我试图把__FILE__和 __LINE__直接填到operator new和operator new[]函数体里边,然后把函数置成inline,结果都输出的是重载operator new和operator new[]的文件和函数体printf函数所在行。然后又试了将operator new的缺省参数设为__FILE__和 __LINE__结果依然,于是想到了用宏定义。
先看看MFC里的做法,MFC为了调试方便,对new进行了宏定义:
#define new DEBUG_NEW
#define DEBUG_NEW new(THIS_FILE, __LINE__)
这里我借用MFC的做法,我也用宏定义:
void * operator new (size_t size, const char* file, const size_t line);
void * operator new [](size_t size, const char* file, const size_t line);
#define MC_NEW new(__FILE__, __LINE__)
#define new MC_NEW
3、将malloc/free 用new/delete替换
为了便于统计malloc/free信息,也用宏定义的方法处理:
#define malloc(s) ((void*)new unsigned char[s])
#define free(p) (delete [] (char*)(p));
4、在数据结构里存储内存使用情况。
下面写一个用于存储new/delete中内存信息的数据结构,可以使用链表,也可以使用哈希表,这里选用哈希表,写一个CHash类。
代码略。
5、为了保证CHash在所有对象析构执行完之后再销毁,应该将CHash放在全局存储区,将其设成static类型,另外,如果有多个static,还需要注意放置的顺序。
到这里这个简易的内存泄露检测工具完成了,但目前还不能用于多线程。
①当两个operator new和operator delete有相等的参数个数,并且除了第一个参数之外其余参数的类型依次完全相同之时,我们称它们为一对匹配的operator new和operator delete。
不过正常情况下带多个参数的delete不会被调用,只有在构建一个对象的过程中,构造函数中发生异常,并且这个异常被捕获了,那么此时C++的异常处理机制才会自动用与被使用的operator new匹配的operator delete来释放内存(补充一点:在operator new中抛出异常不会导致这样的动作,因为系统认为这标志着内存分配失败)。
试验代码:
#include <malloc.h>
struct Base
{
Base()
{
throw int(3);
}
~Base() {}
void* operator new( size_t nSize, const char*,int)
{
void* p = malloc( nSize );
return p;
}
void operator delete( void *p)
{
free(p);
}
void operator delete( void* p,const char*,int)
{
free( p );
}
};
#define new new(__FILE__, __LINE__)
int main( void )
{
Base* p = null;
try
{
p = new Base;
delete p;
}
catch(...)
{
}
return 0;
}
重载全局new/delete实现内存检测的更多相关文章
- C++:重载全局new/delete实现跨平台多线程内存检测
Reference: https://blog.csdn.net/u014023615/article/details/39551191 Reference: https://blog.csdn.ne ...
- [C++] 重载new和delete——控制内存分配
1.new和delete表达式的工作机理 1)new表达式实际执行了三步 string *sp=new string("aaaa"); ];//string采用默认初 ...
- 重载operator new delete函数
可以重载global的operator new delete 函数,细节如下: MyNewDelete.h #pragma once #include <stdlib.h> #includ ...
- 重载new和delete来检测内存泄漏
重载new和delete来检测内存泄漏 1. 简述 内存泄漏属于资源泄漏的一种,百度百科将内存泄漏分为四种:常发性内存泄漏.偶发性内存泄漏.一次性内存泄漏和隐式内存泄漏. 常发性指:内存泄漏的代 ...
- ZT c++ 中的重载全局new,delete
c++ 中的重载全局new,delete 分类: c++ 2010-08-06 10:31 116人阅读 评论(1) 收藏 举报 deletec++file编译器语言工作 最近做一个小项目,对c++又 ...
- 【ThinkingInC++】64、重载new和delete,来模仿内存的分配
/** * 书本:[ThinkingInC++] * 功能:重载new和delete.来模仿内存的分配 * 时间:2014年10月5日14:30:11 * 作者:cutter_point */ #in ...
- C++ 重载new和delete操作符
原因: C++标准库提供的new和delete操作符,是一个通用实现,未针对具体对象做具体分析 存在分配器速度慢.小型对象空间浪费严重等问题,不适用于对效率和内存有限制的应用场景 好处: 灵活的内 ...
- 重载new和delete
当我们创建一个new表达式时,会发生两件事.首先使用operator new()分配内存,然后调用构造函数.在delete表达式里,调用了析构函数,然后使用operator delete()释放内存. ...
- c/c++ 重载new,delete运算符 placement new
重载new,delete运算符 new,delete在c++中也被归为运算符,所以可以重载它们. new的行为: 先开辟内存空间 再调用类的构造函数 开辟内存空间的部分,可以被重载. delete的行 ...
随机推荐
- Google JavaScript样式指南
Google JavaScript样式指南 目录 1简介 1.1术语说明 1.2指南说明 2源文件基础知识 2.1文件名 2.2文件编码:UTF-8 2.3特殊字符 3源文件结构 3.1许可或版权 ...
- JavaScript小细节点罗列(1)
共勉! 属性访问表达式 众所周知,JavaScript为属性的访问定义了两种语法方式: 表达式.标识符 // 表达式(指定对象) 标识符(指定需要访问的属性的名称) 表达式[表达式] //表达式1(指 ...
- WPF ListView 分组 Grouping
在Resource里定义数据源和分组字段: <CollectionViewSource x:Key="listData" Source="{Binding Cate ...
- Flutter学习之制作底部菜单导航
简介 现在我们的 APP 上面都会在屏幕下方有一排的按钮,点击不同的按钮可以进入不同的界面.就是说在界面的底部会有一排的按钮导航.可看下面的图示. 完成图示 程序工程目录 梳理下实现步骤我们需要实现这 ...
- Android 对话框 (AlertDialog)
Android 提供了 AlertDialog 类可通过其内部类 Builder 轻松创建对话框窗口,但是没法对这个对话框窗口进行定制,为了修改 AlertDialog 窗口显示的外观,解决的办法就是 ...
- cookie implements session
cookie实现会话 服务器调用response.addCookie()设置set-cookie响应头后,浏览器收到这个响应头与数值后,会将它以文件的形式存储于本地PC上.当浏览器再次访问同一Web服 ...
- IIS测试环境搭建
1.控制面板->程序->程序和功能->打开或关闭Windows功能->Internet信息服务->Web管理工具,打开如下服务: 2.打开IIS管理器 2.1检查.net ...
- vim和xshell配色
xshell配色: http://www.hookr.cn/xshell-pei-se.html vim配色: 参考该文中的配置方法,包括设置256色等.http://www.cnblogs.com/ ...
- RHEL7系统管理之网络管理
1. RHEL7的网络介绍 在RHEL7中, NetworkManager 提供的默认联网服务是一个动态网络控制和配置守护进程, 支持ifcfg类型的配置文件. NetworkManager 可用于连 ...
- 【Redis】命令学习笔记——哈希(hash)(15个超全字典版)
本篇基于redis 4.0.11版本,学习哈希(hash)相关命令. hash 是一个string类型的field和value的映射表,特别适合用于存储对象. 序号 命令 描述 实例 返回 HSET ...