传统的内存分配:
1.外碎片
当我们只有红色部分申请4字节的内存时,其他的都使用8字节的内存,包括后序的申请都是8字节的空间,那么这个4字节的内存就分配不出去了,这个时候4字节的内存就是外碎片。
2.内碎片
大多都是内存对齐引起的,比如:
struct A
{
int a;
char b;
};
我们知道,在32位机器下,A的大小是8。所以在生成对象的时候是分配了8个字节的空间,但是里面只使用了5字节的内存空间,这就叫做内碎片。
为了实现自主的申请内存,自主的释放内存,不借助系统的操作,提出来池的概念–内存池
- 申请一块大的内存空间,然后后序的操作都是在这一块内存区域上,最后释放一次就好了。所以说现在只要申请一次,释放一次就可以了,到时候大的内存归还,就不容易产生内存碎片了。
- 然后就是设计相应的数据结构,可以标识内存的分配状态:静态链表
- 因为底层是以链表的形式存在的,所以在申请内存的时候,会选择头部的空间,相当于头删,然后让头指针指向下一个节点;在释放内存的时候,相当于头插,并改变pool头指针的指向就可以了。
接下来我用内存池去实现队列:
#include <iostream>
//用内存池实现队列
template<typename T>
class Queue;
const int QueueItem_Count = 10;
//内存池
template<typename T>
class QueueItem
{
public:
QueueItem(T val = T())
:mdata(val),pnext(NULL)
{}
void* operator new(size_t size)
{
if(pool == NULL)
{
pool = (QueueItem<T>*)new char[size*QueueItem_Count];
QueueItem<T>* pCur = pool;
for(pCur;pCur < pool + QueueItem_Count -1;pCur = pCur + 1)
{
pCur->pnext = pCur + 1;
}
pCur->pnext = NULL;
}
void *ptr = pool;
pool = pool->pnext;
return ptr;
}
void operator delete(void *ptr)
{
QueueItem<T>* pqptr = (QueueItem<T>*)ptr;
pqptr->pnext = pool;
pool = pqptr;
}
private:
template<typename T>
friend class Queue;
T mdata;
QueueItem<T> *pnext;
static QueueItem<T>* pool;
};
template<typename T>
QueueItem<T>* QueueItem<T>::pool = NULL;
#pragma warning(disable:4996);
template<typename T>
class Queue
{
public:
Queue()
{
ptail = phead = new QueueItem<T>();
}
~Queue()
{
QueueItem<T>* pCur = phead;
QueueItem<T>* pNext;
while(pCur != NULL)
{
pNext = pCur->pnext;
delete pCur;
pCur = pNext;
}
phead = NULL;
}
void push(T val)
{
QueueItem<T>* pnewitem = new QueueItem<T>(val);
ptail->pnext = pnewitem;
ptail = ptail->pnext;
}
bool Empty()
{
return (phead == ptail) && (phead != NULL);
}
void pop()
{
if(Empty())
{
throw std::exception("Queue is empty!");
}
QueueItem<T>* pCur = phead->pnext;
phead->pnext = pCur->pnext;
delete pCur;
}
T back()
{
if(Empty())
{
throw std::exception("Queue is empty!");
}
return ptail->mdata;
}
T front()
{
if(Empty())
{
throw std::exception("Queue is empty!");
}
return phead->pnext->mdata;
}
private:
QueueItem<T> *phead;
QueueItem<T> *ptail;
};
int main()
{
Queue<int> que;
for(int i = 0;i < 5;++i)
{
que.push(i+1);
}
que.pop();
auto front = que.front();
auto back = que.back();
std::cout << front << std::endl;
std::cout << back << std::endl;
return 0;
}
此设计内存池通用性不高,只能设计队列。
下面是通用内存池的设计:
//通用的内存池
const int MEM_SIZE = 10;
template<typename T>
class MEM_POOL
{
public:
MEM_POOL()
{
pool = NULL;
}
void* Alloc(rsize_t size)
{
if(NULL == pool)
{
pool = (Node*)new char[(size+4)*MEM_SIZE]();
Node* pCur = pool;
for(pCur;pCur < pool + MEM_SIZE -1;pCur = pCur + 1)
{
pCur->next = pCur + 1;
}
pCur->next = NULL;
}
void* rt = pool;
pool = pool->next;
return rt;
}
void Dealloc(void* ptr)
{
Node* pptr = (Node*)ptr;
if(NULL == pptr)
{
return;
}
pptr->next = pool;
pool = pptr;
}
private:
class Node
{
public:
Node(T data):mdata(data),next(NULL){}
public:
T mdata;
Node* next;
};
Node* pool;
};
class Student
{
public:
Student(std::string name,std::string id,int age)
:mname(name),mid(id),mage(age)
{}
void* operator new(size_t size)
{
return mm.Alloc(size);
}
void operator delete(void* ptr)
{
mm.Dealloc(ptr);
}
private:
std::string mname;
std::string mid;
int mage;
static MEM_POOL<Student> mm;
};
MEM_POOL<Student> Student::mm;