重载new和delete,处理内存溢出
2015-03-12 21:41
246 查看
很多时候,我们使用new/delete来分配和释放内存。那么这篇问题主要讲的是,使用new来处理实际编程中可能出现的内存泄漏的问题。奇怪,既然你说delete可以释放内存呢,只要用好这两个函数,保证匹配不就得了。然后这是一种很被动的做法,当内存泄露了,问题显现出来知道时,事态可能已经很严重了。
那么我们该如何处理呢?
主要思路是重载new和delete。
先提供一个如何重载全局new和delete的简单例子。
编译运行得:
creating & destroying an int
operator new:4 Bytes
operator delete
creating & destroying an s
operator new:400 Bytes
S::S()
S::~S()
operator delete
creating & destroying S[3]
operator new:1204 Bytes
S::S()
S::S()
S::S()
S::~S()
S::~S()
S::~S()
operator delete
其实这里看得出new的实质其实是调用malloc,而delete实际上调用free。
分析下创建一个类型S的数组时,所需要的字节,其可以知道额外的内存被分配用于存放它所包含对象的数量的信息。
那么接下来对一个类重载new和delete,为其内存分配系统做些标明,表示哪块存储单元被使用,这里使用了一个字节(byte)数组,一个字节代表一块存储单元。
通过穿件一个能够容纳psize个Framis对象的字节数组的方法,为Framis堆分配了内存。相应地,分配表中也会有psize个成员,其中每一bool类型成员对应一块内存。初始化时,分配表中所有的值都被置为false,第23行。
new()首先对分配表进行搜索,寻找值为false的成员,找到后将该成员设置为true,并且返回这个存储单元的地址。如果找不到任何空闲内存,将会给跟踪文件发送一个消息,并且产生一个bad_alloc类型的异常信息。
关于这里的异常处理:
函数参数表后的throw(bad_alloc),它通知了编译器及用户这个函数可产生一个bad_alloc的异常信息,如果没内存可用时,此函数会由throw bad_alloc语句产生一个异常信息,当异常发生时,函数停止执行并把控制权交给catch子句的异常处理。
c++primer及任何一本讲述c++的书都会讲到异常处理。try后用大括号{}包含了可以产生异常信息的所有代码,程序中表示对Framis对象的new的调用。因此当57行的注释去掉时,因为无法分配内存而throw bad_alloc。
try部分后是一个或多个catch子句,每一个都指明他们获取的异常信息的类型,该程序中,catch(bad_alloc)将会捕获bad_alloc类型的异常,其子句被执行。
在main中,先分配足够多的Framis对象后,61行释放掉一个内存,而后又在64行分配内存,表明释放掉的内存可被重用。
其实这里并没有讲如何去处理,只是提供了一种思路:重载new和delete,实时打印相关信息表示内存的使用情况,通过这些信息我们来做处理,甚至可以说是一种log
那么我们该如何处理呢?
主要思路是重载new和delete。
先提供一个如何重载全局new和delete的简单例子。
//Overload global new/delete #include <cstdio> #include <cstdlib> using namespace std; void * operator new(size_t sz) { printf("operator new:%d Bytes\n",sz); void* m = malloc(sz); if(!m) puts("out of memory"); return m; } void operator delete(void *m) { puts("operator delete"); free(m); } class S{ int i[100]; public: S() {puts("S::S()");} ~S() {puts("S::~S()");} }; int main() { puts("creating & destroying an int"); int* p = new int(47); delete p; puts("creating & destroying an s"); S* s = new S; delete s; puts("creating & destroying S[3]"); S* sa = new S[3]; delete []sa; }
编译运行得:
creating & destroying an int
operator new:4 Bytes
operator delete
creating & destroying an s
operator new:400 Bytes
S::S()
S::~S()
operator delete
creating & destroying S[3]
operator new:1204 Bytes
S::S()
S::S()
S::S()
S::~S()
S::~S()
S::~S()
operator delete
其实这里看得出new的实质其实是调用malloc,而delete实际上调用free。
分析下创建一个类型S的数组时,所需要的字节,其可以知道额外的内存被分配用于存放它所包含对象的数量的信息。
那么接下来对一个类重载new和delete,为其内存分配系统做些标明,表示哪块存储单元被使用,这里使用了一个字节(byte)数组,一个字节代表一块存储单元。
//Local overloaded new & delete #include <cstddef> //size_t #include <fstream> #include <iostream> #include <new> using namespace std; ofstream out("Framis.out"); class Framis{ enum {sz = 10}; char c[sz]; //To take up space,not used static unsigned char pool[]; static bool alloc_map[]; public: enum {psize = 100}; //frami allowed Framis(){ out << "Framis()\n"; } ~Framis(){ out << "~Framis()..."; } void* operator new(size_t) throw(bad_alloc); void operator delete(void*); }; unsigned char Framis::pool[psize * sizeof(Framis)]; bool Framis::alloc_map[psize] = {false}; //size is ignored -- assume a Framis object void* Framis::operator new(size_t) throw(bad_alloc) { for(int i = 0;i < psize;i++) if(!alloc_map[i]) { out<<"using block"<< i <<"..."; alloc_map[i] = true; //Mark it used return pool + (i * sizeof(Framis)); } out << "out of memory" <<endl; throw bad_alloc(); } void Framis::operator delete(void* m) { if(!m) // check for null pointer return; //Assume it was created in the pool //Calculate which block number it is: unsigned long block = (unsigned long)m - (unsigned long)pool; block /= sizeof(Framis); out<< "freeing block"<<block <<endl; //Mark it free: alloc_map[block] = false; } int main() { Framis* f[Framis::psize]; try{ for(int i = 0;i < Framis::psize;i++) f[i] = new Framis; // new Framis; //out of memory }catch(bad_alloc){ cerr<<" Out of memory!"<<endl; } delete f[10]; f[10] = 0; //Use released memory; Framis* x = new Framis; delete x; for(int j = 0;j < Framis::psize;j++) delete f[j];//Delete f[10] ok }
通过穿件一个能够容纳psize个Framis对象的字节数组的方法,为Framis堆分配了内存。相应地,分配表中也会有psize个成员,其中每一bool类型成员对应一块内存。初始化时,分配表中所有的值都被置为false,第23行。
new()首先对分配表进行搜索,寻找值为false的成员,找到后将该成员设置为true,并且返回这个存储单元的地址。如果找不到任何空闲内存,将会给跟踪文件发送一个消息,并且产生一个bad_alloc类型的异常信息。
关于这里的异常处理:
函数参数表后的throw(bad_alloc),它通知了编译器及用户这个函数可产生一个bad_alloc的异常信息,如果没内存可用时,此函数会由throw bad_alloc语句产生一个异常信息,当异常发生时,函数停止执行并把控制权交给catch子句的异常处理。
c++primer及任何一本讲述c++的书都会讲到异常处理。try后用大括号{}包含了可以产生异常信息的所有代码,程序中表示对Framis对象的new的调用。因此当57行的注释去掉时,因为无法分配内存而throw bad_alloc。
try部分后是一个或多个catch子句,每一个都指明他们获取的异常信息的类型,该程序中,catch(bad_alloc)将会捕获bad_alloc类型的异常,其子句被执行。
在main中,先分配足够多的Framis对象后,61行释放掉一个内存,而后又在64行分配内存,表明释放掉的内存可被重用。
其实这里并没有讲如何去处理,只是提供了一种思路:重载new和delete,实时打印相关信息表示内存的使用情况,通过这些信息我们来做处理,甚至可以说是一种log
相关文章推荐
- 如何检测内存泄漏——重载new和delete
- C++中malloc/free与new/delete的区别及内存分配失败错误处理
- 如何检测内存泄漏——重载new和delete
- [转]如何检测内存泄漏——重载new和delete
- 如何检测内存泄漏——重载new和delete
- C++动态内存:(二)重载new和delete
- 如何检测内存泄漏——重载new和delete
- 重载new和delete方法实现C++内存安全
- 通过重载new与delete运算符避免向系统重复申请内存从而提高程序运行效率的办法
- 【ThinkingInC++】64、重载new和delete,来模仿内存的分配
- 重载new和delete方法实现C++内存安全
- 如何检测内存泄漏——重载new和delete
- C++中malloc/free与new/delete的区别及内存分配失败错误处理
- C++中malloc/free与new/delete的区别及内存分配失败错误处理
- 重载new和delete来检测内存泄漏
- 控制内存分配----重载new和delete & 定位new表达式
- 内存泄露:重载new delete
- 重载new和delete来检测内存泄漏
- 如何检测内存泄漏——重载new和delete
- C++中malloc/free与new/delete的区别及内存分配失败错误处理