基本设计思路:
内存分配的最小单位为8字节,称为内存块,一次分配若干连续的内存块,称为内存池。
类似sgi stl的做法,取一个数组作为内存分配的入口,每个入口都只能分配大小为8的倍数的内存,而数组的下标就是用来确定这个倍数。
每个入口都维护一个链表,链表的节点
当申请内存时,根据申请的字节数确定入口后,看当前链表是否有节点可用,有就分配出去,没有就向内存池申请。
回收内存时,将内存块直接挂回链表的头部,而不是返回给内存池
最大优点是:内存碎片为0,分配回收效率较高
最大缺点是:运行时的内存占有量只增不减,但增长比较缓慢
/*
* File: Allocator.h
* Author: Administrator
*
* Created on 2011年3月15日, 下午3:10
*/
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
#include <iostream>
using namespace std;
const int ENTRY_COUNT = 16; //提供16个内存池分配入口
const int BLOCK_SIZE = 8; //内存块的大小
const int POOL_SIZE = 256; //内存池中的内存块个数
const int MAX_SIZE = ENTRY_COUNT*BLOCK_SIZE; //一次最大可分配的字节数,大于时将采用普通的new
namespace zlh {
template<class T>
class Allocator {
private:
//内存块,分配的最小单位
union MemoryBlock {
MemoryBlock() : next(0) {
}
MemoryBlock* next;
unsigned char buf[BLOCK_SIZE];
};
//内存池,管理内存块
struct MemoryPool {
MemoryPool() : vernier(0), next(0) {
}
int remain() //获取剩余块数
{
return POOL_SIZE - vernier;
}
void alloc(int index) //给entry[index]分配空间
{
pool[vernier].next = entry[index];
entry[index] = &pool[vernier];
vernier = vernier + index + 1;
}
MemoryPool* next;
int vernier; //游标,从该处开始分配
MemoryBlock pool[POOL_SIZE];
};
private:
static MemoryPool* firstPool; //从该指针指向的池分配空间
static MemoryBlock** entry; //分配空间的入口
public:
Allocator() {
///初始化分配入口
entry = new MemoryBlock*[ENTRY_COUNT];
for (int i = 0; i < ENTRY_COUNT; i++)
entry[i] = 0;
///必须保证firstPool不为0
if (firstPool == 0) {
firstPool = new MemoryPool();
}
}
~Allocator() {
MemoryPool* temp;
while (firstPool != 0) {
temp = firstPool;
firstPool = firstPool->next;
delete[] temp;
}
delete[] entry;
}
//分配大小为cnt*sizeof(T)的空间
T* allocate(int cnt) {
int size = cnt * sizeof (T);
if (size > MAX_SIZE) {//大于MAX_SIZE采用普通的new
return new T[cnt];
}
int index = size / 8; //确定分配入口
if (entry[index] != 0) {//该入口是否有可分配的内存
MemoryBlock* temp = entry[index];
entry[index] = entry[index]->next;
return (T*) temp;
} else {//没有就向pool申请
innerAlloc(index);
allocate(cnt);
}
}
void deallocate(T* ptr, int cnt) {
int size = cnt * sizeof (T);
if (size > MAX_SIZE) {
delete[] ptr;
return;
}
int index = size / 8;
MemoryBlock* temp = (MemoryBlock*) ptr;
temp->next = entry[index]; //将回收的内存块挂接到入口链首
entry[index] = temp;
}
//构造一个T对象
template<class T1>
T* construct(T1 value1) {
T* ptr = allocate(1);
new(ptr) T(value1);
return ptr;
}
//构造一个T对象
template<class T1, class T2>
void construct(T1 value1, T2 value2) {
T* ptr = allocate(1);
new(ptr) T(value1, value2);
return ptr;
}
//销毁该对象
void destruct(T* ptr) {
ptr->~T();
deallocate(ptr, 1);
}
private:
void innerAlloc(int index) {
int remain = firstPool->remain(); //获取当前pool的剩余块数
if (index + 1 > remain) {//当申请的块数大于剩余块数
if (remain > 0)//将剩余的块一次性分配给合适的入口
firstPool->alloc(remain - 1);
extend(); //然后申请新的pool
innerAlloc(index);
} else {//满足申请时直接分配
firstPool->alloc(index);
}
}
void extend() {
MemoryPool* newPool = new MemoryPool();
newPool->next = firstPool;
firstPool = newPool;
}
};
template<class T>
class Allocator<T>::MemoryBlock** Allocator<T>::entry = 0;
template<class T>
class Allocator<T>::MemoryPool* Allocator<T>::firstPool = 0;
}
#endif /* ALLOCATOR_H */