在C++中,指针往往忘记释放。引起内存泄露。

1.内存泄露指:

    内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。

    内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。

    然后今天做了一个内存泄露检测工具,准确来说是定义了一个接口,通过这个接口来实现类存泄露的解决。

    

2.设计思路:

    通过自己定义的接口,将我们开辟的指针都存储到一个指针相关信息的链表中。将链表定义为全局变量。然后通过全局变量来确定我们所有动态开辟空间的详细信息表,也可以使用单例模式来解决。大概的图解就是:wKiom1Z-Sj_h_4jZAAA1t9XeL1w714.png然后我们首先定义出节点类型:

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;
}

完成了。大家只要具备基本的知识,认真去看会做出来的。