使用内存池的原因:
在c++开辟空间和释放空间使用的是new和delete,而new和delete是对内存的操作,对内存进行操作必然需要从用户态转到入内核态,系统在接收到分配一定大小内存请求时,首先查找内部维护的内存空闲块表,并且需要一定的算法找到合适的内存块,由此频繁的new和delect会降低效率,并且在内存中会产生外碎片。默认的内存管理函数还考虑到多线程的应用,需要在每次分配和释放内存时加锁,同样有增加开销。为了解决这些问题,就有了内存池的概念。。。。
内存池的介绍以及优点:
内存池,池的概念就是一组资源的集合,简单来说,内存池就是实现一种对内存的管理机制。使用内存池有以下的优点:
1)对于需要频繁分配释放固定大小的内存对象时,不需要复杂的分配算法和多线程保护,也不需要维护内存空闲表的额外开销。
2)一次会开辟大量连续的空间作为内存池,提高了程序的性能,不会产生大量的外碎片,同时不用多次进入内核态。
内存池的解析
这里使用静态链表实现内存池,什么是静态链表呢,就是以数组的形式存在能做链表的事情,如图是实现内存池的图解:
pool:指向内存池的一个标识,指向内存池中第一块未使用的内存块
数据域:内存块要被使用时,需要存放的数据
指针域:指向下一块未使用的内存块
alloc():在pool为NULL的时候,实现开辟一块大的内存;并且实现内存块的分配
dealloc():实现内存块释放后,归还到内存池中;
图解内存管理机制的过程:
完整的代码实现:
#include <iostream>
template <typename T>
class Memory_Pool
//内存池
{
public:
void* alloc(size_t size)
//实现对空间的开辟(内存块的使用)
{
if(pool == NULL)
{
pool = (Node*)new char[(size + 4) * 10]();//开辟一个大的内存,里面有十个内存块
Node* pcur = pool;
for(pcur;pcur < pool + 10 -1;pcur = pcur + 1)
{
pcur->pnext = pcur + 1;//指针域使得各个内存块完成连接
}
pcur->pnext = NULL;//最后一个内存块的指针域肢痿空
Node* prt = pool;
pool = pool->pnext;//不能是pool = pool + 1 因为可能下一个内存块已经使用,而pnext可以指向下一个未使用的内存块
return prt;
}
}
void* dealloc(void* ptr)
//实现对空间的释放(内存块的归还)使用头插的方法
{
Node* prt = pool;
prt->pnext = pool;
pool = prt;
}
private:
class Node
//内存池中的内存块
{
public:
Node(T val = T()):mdata(val),pnext(NULL){}
public:
T mdata;//数据域
Node* pnext;//指针域
};
static Node* pool;//指向内存池的静态指针,多个对象共用一个内存池
};
template<typename T>
typename Memory_Pool<T>::Node* Memory_pool<T>::pool = NULL;//对pool进行初始化;typename的作用是告诉编译器Node*是一个类型
class Test
{
public:
Test(int a):ma(a){}
void* operator new(size_t size)
{
return mp.alloc(size);
}
void operator delete(void* ptr)
{
mp.dealloc(ptr);
}
private:
int ma;
static Memory_Pool<Test> mp;
};
Memory_Pool<Test> Test::mp;
int main()
{
Test* ptest = NULL;
for(int i = 0;i < 20;i++)
{
ptest = new Test(20);
}
return 0;
}