在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;
}
完成了。大家只要具备基本的知识,认真去看会做出来的。
本文出自 “剩蛋君” 博客,转载请与作者联系!