在C++中,指针往往忘记释放。引起内存泄露。
1.内存泄露指:
内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。
然后今天做了一个内存泄露检测工具,准确来说是定义了一个接口,通过这个接口来实现类存泄露的解决。
2.设计思路:
通过自己定义的接口,将我们开辟的指针都存储到一个指针相关信息的链表中。将链表定义为全局变量。然后通过全局变量来确定我们所有动态开辟空间的详细信息表,也可以使用单例模式来解决。大概的图解就是:然后我们首先定义出节点类型:
struct MemListNode { void* _ptr; string _file; int _line; //只用书写构造函数 MemListNode(void* ptr = 0,const char* file = "",int line = 0) :_ptr(ptr) ,_file(file) ,_line(line) {} };
然后我们定义全局变量,利用宏命令,模板,还有类型萃取完成我们内存泄露检测的功能实现:
MemoryCheck.hpp
#include <iostream> #include<assert.h> #include<list> #include<string> #include"TypeTraits.hpp" using namespace std; #define NEW(type) __new<type>(sizeof(type),__FILE__,__LINE__) #define DELETE(type,ptr) __delete<type>(ptr) #define NEW_ARRAY(type,num) __newArray<type>(sizeof(type)*num+4,__FILE__,__LINE__,num) #define DELETE_ARRAY(type,ptr) __deleteArray<type>(ptr) struct MemListNode { void* _ptr; string _file; int _line; //只用书写构造函数 MemListNode(void* ptr = 0,const char* file = "",int line = 0) :_ptr(ptr) ,_file(file) ,_line(line) {} }; list<MemListNode> MemList; void* Alloc(size_t size,const char* file,int line) { void *ptr = malloc(size); if(ptr) { MemListNode info(ptr,file,line); MemList.push_back(info); } return ptr; } void Dealloc(void* ptr) { void* del = ptr; if(ptr) { list<MemListNode>::iterator it = MemList.begin(); while(MemList.end() != it) { if(it->_ptr == ptr) { MemList.erase(it); free(del); return; } ++it; } printf("释放的指针没有申请空间\n"); } } template<class T> T* __new(size_t size,const char* file,int line) { T* ptr = (T*)Alloc(size,file,line); if(TypeTraits<T>::__IsPODType().Get()) { return ptr; } else { return new(ptr) T; } } template<class T> void __delete(T* ptr) { if(TypeTraits<T>::__IsPODType().Get()) { Dealloc(ptr); } else { ptr->~T(); Dealloc(ptr); } } template<class T> T* __newArray(size_t size,const char* file,int line,size_t num) { T* ptr = (T*)Alloc(size,file,line); if(TypeTraits<T>::__IsPODType().Get()) { return ptr; } else { *(int *)ptr = num; T* cur = (T*)((int)ptr+4); for(int i =0;i < num;++i) { new(cur)T; cur = (T*)((int)cur + sizeof(T)); } return ptr; } } template<class T> void __deleteArray(T* ptr) { if(TypeTraits<T>::__IsPODType().Get()) { Dealloc(ptr); } else { int num = *((int *)ptr); T* cur = (T*)((int)ptr+4); for(int i = 0;i < num;++i) { cur->~T(); cur = (T*)((int)cur + sizeof(T)); } Dealloc(ptr); } } void print() { list<MemListNode>::iterator it = MemList.begin(); if(MemList.end() == it) { cout<<"指针已经全部释放"<<endl; } while(MemList.end() != it) { int i = 1; printf("%d:指针地址%p,文件名:%s,行号:%d\n",i++,it->_ptr,it->_file.c_str(),it->_line); ++it; } }
类型萃取我们单独写一个文件:
#pragma once #include<iostream> using namespace std; struct __TrueType { bool Get() { return true; } }; struct __FalseType { bool Get() { return false; } }; template <class _Tp> struct TypeTraits { typedef __FalseType __IsPODType; }; template <> struct TypeTraits< bool> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< char> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< unsigned char > { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< short> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< unsigned short > { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< int> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< unsigned int > { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< long> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< unsigned long > { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< long long > { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< unsigned long long> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< float> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< double> { typedef __TrueType __IsPODType; }; template <> struct TypeTraits< long double > { typedef __TrueType __IsPODType; }; template <class _Tp> struct TypeTraits< _Tp*> { typedef __TrueType __IsPODType; };
简单的测试用例:
#include"MemoryChilke.hpp" #include"TypeTraits.hpp" void Test() { string* p1 = NEW(string); DELETE(string,p1); int *p2 = NEW(int); string* p3 = NEW_ARRAY(string,10); DELETE_ARRAY(string,p3); print(); } int main() { Test(); return 0; }
完成了。大家只要具备基本的知识,认真去看会做出来的。
本文出自 “剩蛋君” 博客,转载请与作者联系!
原文地址:http://memory73.blog.51cto.com/10530560/1728576